diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 000000000..79044b633 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,37 @@ +When reporting issues please provide the following information: + +[See this for more information on reporting issues for KSP Mods](http://forum.kerbalspaceprogram.com/?showtopic=83212) + +[See the Original Forum Post (OP) for additional info](http://forum.kerbalspaceprogram.com/?showtopic=155014) + +##### ISSUE TYPE + + - Support ( Need help getting something to work) + - Bug Report (Something is broken) + - Feature Idea (Something new you want to see) + - Enhancement (Expand on existing features) + + +##### KSP and BDA Version + +``` + +``` + +##### OS / ENVIRONMENT + + +##### SUMMARY + + +##### STEPS TO REPRODUCE + + + +##### Log Files + + + diff --git a/.gitignore b/.gitignore index ac8982661..9b200b5d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,84 @@ +####################################### +BDArmory Ignore +####################################### +BDArmory/BDArmory.csproj.user +_LocalDev + +BahaTurret/.vs +BahaTurret/obj +BahaTurret/bin/Debug/ +BDArmory/.vs +BDArmory/obj +BDArmory/bin/Debug/ + +BahaTurret/.vs/config +BahaTurret/LocalDev/7za_dir.txt +BahaTurret/LocalDev/dist_dir.txt +BahaTurret/LocalDev/ksp_dir.txt +BahaTurret/LocalDev/ksp_production_dir.txt +BahaTurret/LocalDev/mono_exe.txt +BahaTurret/LocalDev/pdb2mdb_exe.txt +BahaTurret/BahaTurret.userprefs +BahaTurret/bin/Release + +BDArmory/.vs +BDArmory.Core/.vs + +BDArmory/obj +BDArmory/bin/Debug/ + +BDArmory/.vs/config +BDArmory/LocalDev/7za_dir.txt +BDArmory/LocalDev/dist_dir.txt +BDArmory/LocalDev/ksp_dir.txt +BDArmory/LocalDev/ksp_production_dir.txt +BDArmory/LocalDev/mono_exe.txt +BDArmory/LocalDev/pdb2mdb_exe.txt +BDArmory/BahaTurret.userprefs +BDArmory/Distribution/GameData/BDArmory/Plugins/BDArmory.Core.dll +BDArmory/Distribution/GameData/BDArmory/Plugins/BDArmory.dll + +BDArmory/packages + +BDArmory.Core/obj/Debug/BDArmory.Core.csproj.FileListAbsolute.txt +BDArmory.Core/obj/Release/BDArmory.Core.csproj.FileListAbsolute.txt +BDArmory/bin/Debug +BDArmory.Core/obj/ +BDArmory.Core/.vs +BDArmory.Core/packages.config +BDArmory/packages.config +BDArmory.Multiplayer/obj +BDArmory.Core/bin/Debug/Assembly-CSharp.dll +BDArmory.Core/bin/Debug/BDArmory.Core.dll +BDArmory.Core/bin/Debug/KSPAssets.dll +BDArmory.Core/bin/Debug/UnityEngine.dll +BahaTurret/BDArmory.sln.DotSettings.user +BahaTurret/BDArmory.csproj.user +BDArmory.Core/bin/Debug/UnityEngine.UI.dll + + +####################################### +Unity Ignore +####################################### + +TrackIRUnity.dll +Mono* +TDx* +*.pdb +*.jar +*.bat +*.zip +KSPCore.dll +KSPUtil.dll +SaveUpgradePipeline.Core.dll +UnityEngine.xml +Vectrosity.dll + +####################################### +####################################### +System* +mscorlib.dll + # Windows image file caches Thumbs.db ehthumbs.db @@ -33,24 +114,50 @@ Icon # Files that might appear on external disk .Spotlight-V100 .Trashes - -TrackIRUnity.dll -Assembly-* -Mono* -mscorlib.dll -System* -TDx* -UnityEngine.dll -*.pdb -*.jar -*.bat - -BahaTurret/BahaTurret.userprefs -*.zip -KSPAssets.dll -KSPCore.dll -KSPUtil.dll -SaveUpgradePipeline.Core.dll -UnityEngine.UI.dll -UnityEngine.xml -Vectrosity.dll +/.vs +/.vs +/.vs/slnx.sqlite +/.vs/ProjectSettings.json +/.vs/BDArmory_JRODRIGV/v15/Browse.VC.db +/.vs/BDArmory_JRODRIGV/v15 +/.vs/slnx.sqlite +/BahaTurret/bin/Release +/BDArmory.Core/obj/Debug/BDArmory.Core.csproj.FileListAbsolute.txt +/BDArmory.Core/obj/Release/BDArmory.Core.csproj.FileListAbsolute.txt +/BDArmory/bin/Debug +BDArmory.Core/obj/ +/BDArmory.Multiplayer/obj +BDArmory.Core/bin/Debug/Assembly-CSharp.dll +BDArmory.Core/bin/Debug/BDArmory.Core.dll +BDArmory.Core/bin/Debug/KSPAssets.dll +BDArmory.Core/bin/Debug/UnityEngine.dll +BahaTurret/BDArmory.sln.DotSettings.user +BahaTurret/BDArmory.csproj.user +BDArmory.Core/bin/Debug/UnityEngine.UI.dll +BDArmory/LocalDev/Refs/UnityEngine.UI.dll +BDArmory/LocalDev/Refs/KSPAssets.dll +BDArmory/LocalDev/Refs/Assembly-CSharp.dll +BDArmory/LocalDev/Refs/Assembly-CSharp-firstpass.dll +BDArmory/LocalDev/Refs/UnityEngine.dll +/BDArmory/UpgradeLog3.htm +/BDArmory/UpgradeLog2.htm +/BDArmory/UpgradeLog.htm +/BDArmory/bin/Release +/BDArmory.Core/bin +/BDArmory.Guidance/bin/Release +/BDArmory.Guidance/obj/Release +/BDArmory/BDArmory.sln.DotSettings.user +/BDArmory.Events/obj/Debug +/BDArmory/LocalDev/Refs +/BDArmory.Events/obj/Release +/Binaries +/BDArmory/Distribution/GameData/BDArmory/Plugins +/BDArmory/_ReSharper.Caches/ReSharperPlatformVs15182_74c703de.BDArmory.00 +/packages/Microsoft.Net.Compilers.2.8.0 +/_ReSharper.Caches/ReSharperPlatformVs15182_74c703de.BDArmory.00 +/BDArmory/_ReSharper.Caches/ReSharperPlatformVs15183_74c703de.BDArmory.00 +/BDArmory/_ReSharper.Caches/ReSharperPlatformVs16191_4011600b.BDArmory.00 +/BDArmory/_ReSharper.Caches/ReSharperPlatformVs16191_4011600b.BDArmory.01 +/_ReSharper.Caches/ReSharperPlatformVs16191_4011600b.00 +/BDArmory/_ReSharper.Caches/ReSharperPlatformVs16193_4011600b.BDArmory.00 +/_ReSharper.Caches/ReSharperPlatformVs16193_4011600b.00 diff --git a/.gitignore.orig b/.gitignore.orig new file mode 100644 index 000000000..85798bec2 --- /dev/null +++ b/.gitignore.orig @@ -0,0 +1,121 @@ +####################################### +BDArmory Ignore +####################################### +BDArmory/BDArmory.csproj.user + +BahaTurret/.vs +BahaTurret/obj +BahaTurret/bin/Debug/ +BDArmory/.vs +BDArmory/obj +BDArmory/bin/Debug/ + +BahaTurret/.vs/config +BahaTurret/LocalDev/7za_dir.txt +BahaTurret/LocalDev/dist_dir.txt +BahaTurret/LocalDev/ksp_dir.txt +BahaTurret/LocalDev/ksp_production_dir.txt +BahaTurret/LocalDev/mono_exe.txt +BahaTurret/LocalDev/pdb2mdb_exe.txt +BahaTurret/BahaTurret.userprefs + +BDArmory/.vs +BDArmory/obj +BDArmory/bin/Debug/ + +BDArmory/.vs/config +BDArmory/LocalDev/7za_dir.txt +BDArmory/LocalDev/dist_dir.txt +BDArmory/LocalDev/ksp_dir.txt +BDArmory/LocalDev/ksp_production_dir.txt +BDArmory/LocalDev/mono_exe.txt +BDArmory/LocalDev/pdb2mdb_exe.txt +BDArmory/BahaTurret.userprefs + + +####################################### +Unity Ignore +####################################### + +TrackIRUnity.dll +Mono* +TDx* +*.pdb +*.jar +*.bat +*.zip +KSPCore.dll +KSPUtil.dll +SaveUpgradePipeline.Core.dll +UnityEngine.xml +Vectrosity.dll + +####################################### +####################################### +System* +mscorlib.dll + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Icon must ends with two \r. +Icon +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes +/.vs +/.vs +/.vs/slnx.sqlite +/.vs/ProjectSettings.json +/.vs/BDArmory_JRODRIGV/v15/Browse.VC.db +/.vs/BDArmory_JRODRIGV/v15 +/.vs/slnx.sqlite +/BahaTurret/bin/Release +/BDArmory.Core/obj/Debug/BDArmory.Core.csproj.FileListAbsolute.txt +/BDArmory/bin/Debug +/BDArmory.Core/obj +/BDArmory.Multiplayer/obj +<<<<<<< HEAD +BahaTurret/BDArmory.sln.DotSettings.user +BDArmory.Core/bin/Debug/UnityEngine.dll +BDArmory.Core/bin/Debug/KSPAssets.dll +BDArmory.Core/bin/Debug/BDArmory.Core.dll +BDArmory.Core/bin/Debug/Assembly-CSharp.dll +BDArmory.Core/bin/Debug/UnityEngine.UI.dll +BahaTurret/BDArmory.csproj.user +======= +BDArmory.Core/bin/Debug/Assembly-CSharp.dll +BDArmory.Core/bin/Debug/BDArmory.Core.dll +BDArmory.Core/bin/Debug/KSPAssets.dll +BDArmory.Core/bin/Debug/UnityEngine.dll +BahaTurret/BDArmory.sln.DotSettings.user +BahaTurret/BDArmory.csproj.user +BDArmory.Core/bin/Debug/UnityEngine.UI.dll +>>>>>>> 311105e5c29cb0a842f90aa18021dbbdf54390a8 diff --git a/BDArmory.Core/BDAPersistantSettingsField.cs b/BDArmory.Core/BDAPersistantSettingsField.cs new file mode 100644 index 000000000..a3ee83246 --- /dev/null +++ b/BDArmory.Core/BDAPersistantSettingsField.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Core +{ + [AttributeUsage(AttributeTargets.Field)] + public class BDAPersistantSettingsField : Attribute + { + public BDAPersistantSettingsField() + { + } + + public static void Save() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + + if (!fileNode.HasNode("BDASettings")) + { + fileNode.AddNode("BDASettings"); + } + + ConfigNode settings = fileNode.GetNode("BDASettings"); + IEnumerator field = typeof(BDArmorySettings).GetFields().AsEnumerable().GetEnumerator(); + while (field.MoveNext()) + { + if (field.Current == null) continue; + if (!field.Current.IsDefined(typeof(BDAPersistantSettingsField), false)) continue; + + settings.SetValue(field.Current.Name, field.Current.GetValue(null).ToString(), true); + } + field.Dispose(); + fileNode.Save(BDArmorySettings.settingsConfigURL); + } + + public static void Load() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + if (!fileNode.HasNode("BDASettings")) return; + + ConfigNode settings = fileNode.GetNode("BDASettings"); + + IEnumerator field = typeof(BDArmorySettings).GetFields().AsEnumerable().GetEnumerator(); + while (field.MoveNext()) + { + if (field.Current == null) continue; + if (!field.Current.IsDefined(typeof(BDAPersistantSettingsField), false)) continue; + + if (!settings.HasValue(field.Current.Name)) continue; + object parsedValue = ParseValue(field.Current.FieldType, settings.GetValue(field.Current.Name)); + if (parsedValue != null) + { + field.Current.SetValue(null, parsedValue); + } + } + field.Dispose(); + } + + public static object ParseValue(Type type, string value) + { + if (type == typeof(string)) + { + return value; + } + + if (type == typeof(bool)) + { + return Boolean.Parse(value); + } + else if (type.IsEnum) + { + return System.Enum.Parse(type, value); + } + else if (type == typeof(float)) + { + return Single.Parse(value); + } + else if (type == typeof(int)) + { + return int.Parse(value); + } + else if (type == typeof(Single)) + { + return Single.Parse(value); + } + else if (type == typeof(Rect)) + { + string[] strings = value.Split(','); + int xVal = Int32.Parse(strings[0].Split(':')[1].Split('.')[0]); + int yVal = Int32.Parse(strings[1].Split(':')[1].Split('.')[0]); + int wVal = Int32.Parse(strings[2].Split(':')[1].Split('.')[0]); + int hVal = Int32.Parse(strings[3].Split(':')[1].Split('.')[0]); + Rect rectVal = new Rect + { + x = xVal, + y = yVal, + width = wVal, + height = hVal + }; + return rectVal; + } + Debug.LogError("[BDArmory]: BDAPersistantSettingsField to parse settings field of type " + type + + " and value " + value); + + return null; + } + } +} diff --git a/BDArmory.Core/BDArmory.Core.csproj b/BDArmory.Core/BDArmory.Core.csproj new file mode 100644 index 000000000..73edc0750 --- /dev/null +++ b/BDArmory.Core/BDArmory.Core.csproj @@ -0,0 +1,121 @@ + + + + + Debug + AnyCPU + {A6F1753E-9570-4C40-AF72-A179890582E5} + Library + Properties + BDArmory.Core + BDArmory.Core + v4.7.2 + 512 + + + + true + portable + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + 6 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + 6 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + ..\..\_LocalDev\KSPRefs\Assembly-CSharp.dll + + + False + ..\..\_LocalDev\KSPRefs\KSPAssets.dll + + + + False + ..\..\_LocalDev\KSPRefs\UnityEngine.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.AnimationModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.AssetBundleModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.CoreModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.ImageConversionModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.IMGUIModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.InputLegacyModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.InputModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.PhysicsModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.TextCoreModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.TextRenderingModule.dll + + + False + ..\..\_LocalDev\KSPRefs\UnityEngine.UI.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.UIElementsModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.UIModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.UnityWebRequestWWWModule.dll + + + + \ No newline at end of file diff --git a/BDArmory.Core/BDArmorySettings.cs b/BDArmory.Core/BDArmorySettings.cs new file mode 100644 index 000000000..d04db0b7c --- /dev/null +++ b/BDArmory.Core/BDArmorySettings.cs @@ -0,0 +1,62 @@ +namespace BDArmory.Core +{ + public class BDArmorySettings + { + public static string settingsConfigURL = "GameData/BDArmory/settings.cfg"; + + [BDAPersistantSettingsField] public static bool INSTAKILL = false; + [BDAPersistantSettingsField] public static bool BULLET_HITS = true; + [BDAPersistantSettingsField] public static bool BULLET_DECALS = true; + [BDAPersistantSettingsField] public static int MAX_NUM_BULLET_DECALS = 200; + [BDAPersistantSettingsField] public static bool SHOW_AMMO_GAUGES = false; + [BDAPersistantSettingsField] public static bool EJECT_SHELLS = true; + [BDAPersistantSettingsField] public static bool SHELL_COLLISIONS = true; + [BDAPersistantSettingsField] public static bool INFINITE_AMMO = false; + [BDAPersistantSettingsField] public static bool DRAW_DEBUG_LINES = false; + [BDAPersistantSettingsField] public static bool DRAW_DEBUG_LABELS = false; + [BDAPersistantSettingsField] public static bool DRAW_AIMERS = true; + [BDAPersistantSettingsField] public static bool AIM_ASSIST = true; + [BDAPersistantSettingsField] public static bool REMOTE_SHOOTING = false; + [BDAPersistantSettingsField] public static bool BOMB_CLEARANCE_CHECK = true; + [BDAPersistantSettingsField] public static float MAX_BULLET_RANGE = 8000f; //TODO: remove all references to this so it can be deprecated! all ranges should be supplied in part config! + [BDAPersistantSettingsField] public static float TRIGGER_HOLD_TIME = 0.3f; + [BDAPersistantSettingsField] public static float TARGET_CAM_RESOLUTION = 1024f; + [BDAPersistantSettingsField] public static bool BW_TARGET_CAM = true; + [BDAPersistantSettingsField] public static float SMOKE_DEFLECTION_FACTOR = 10f; + [BDAPersistantSettingsField] public static float RWR_WINDOW_SCALE_MIN = 0.50f; + [BDAPersistantSettingsField] public static float RWR_WINDOW_SCALE = 1f; + [BDAPersistantSettingsField] public static float RWR_WINDOW_SCALE_MAX = 1.50f; + [BDAPersistantSettingsField] public static float RADAR_WINDOW_SCALE_MIN = 0.50f; + [BDAPersistantSettingsField] public static float RADAR_WINDOW_SCALE = 1f; + [BDAPersistantSettingsField] public static float RADAR_WINDOW_SCALE_MAX = 1.50f; + [BDAPersistantSettingsField] public static float TARGET_WINDOW_SCALE_MIN = 0.50f; + [BDAPersistantSettingsField] public static float TARGET_WINDOW_SCALE = 1f; + [BDAPersistantSettingsField] public static float TARGET_WINDOW_SCALE_MAX = 2f; + [BDAPersistantSettingsField] public static float BDARMORY_UI_VOLUME = 0.35f; + [BDAPersistantSettingsField] public static float BDARMORY_WEAPONS_VOLUME = 0.32f; + [BDAPersistantSettingsField] public static float MAX_GUARD_VISUAL_RANGE = 40000f; + [BDAPersistantSettingsField] public static float MAX_ACTIVE_RADAR_RANGE = 40000f; //NOTE: used ONLY for display range of radar windows! Actual radar range provided by part configs! + [BDAPersistantSettingsField] public static float MAX_ENGAGEMENT_RANGE = 40000f; //NOTE: used ONLY for missile dlz parameters! + [BDAPersistantSettingsField] public static float GLOBAL_LIFT_MULTIPLIER = 0.20f; + [BDAPersistantSettingsField] public static float GLOBAL_DRAG_MULTIPLIER = 4f; + [BDAPersistantSettingsField] public static float IVA_LOWPASS_FREQ = 2500f; + [BDAPersistantSettingsField] public static bool PEACE_MODE = false; + [BDAPersistantSettingsField] public static bool IGNORE_TERRAIN_CHECK = false; + [BDAPersistantSettingsField] public static bool DISPLAY_PATHING_GRID = false; //laggy when the grid gets large + [BDAPersistantSettingsField] public static bool ADVANCED_EDIT = false; //Used for debug fields not nomrally shown to regular users + + [BDAPersistantSettingsField] public static float RECOIL_FACTOR = 0.75f; + [BDAPersistantSettingsField] public static float DMG_MULTIPLIER = 100f; + [BDAPersistantSettingsField] public static float BALLISTIC_DMG_FACTOR = 1f; + [BDAPersistantSettingsField] public static float HITPOINT_MULTIPLIER = 2.0f; + [BDAPersistantSettingsField] public static float EXP_DMG_MOD_BALLISTIC; + [BDAPersistantSettingsField] public static float EXP_DMG_MOD_MISSILE; + [BDAPersistantSettingsField] public static float EXP_IMP_MOD; + [BDAPersistantSettingsField] public static bool FIRE_FX_IN_FLIGHT = false; + [BDAPersistantSettingsField] public static int MAX_FIRES_PER_VESSEL = 10; //controls fx for penetration only for landed or splashed + [BDAPersistantSettingsField] public static float FIRELIFETIME_IN_SECONDS = 90f; //controls fx for penetration only for landed or splashed + [BDAPersistantSettingsField] public static bool PERFORMANCE_LOGGING = false; + [BDAPersistantSettingsField] public static bool AUTOCATEGORIZE_PARTS = true; + [BDAPersistantSettingsField] public static bool SHOW_CATEGORIES = false; + } +} diff --git a/BDArmory.Core/Bootstrapper.cs b/BDArmory.Core/Bootstrapper.cs new file mode 100644 index 000000000..7ff908ecf --- /dev/null +++ b/BDArmory.Core/Bootstrapper.cs @@ -0,0 +1,14 @@ +using BDArmory.Core.Services; +using UnityEngine; + +namespace BDArmory.Core +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class Bootstrapper : MonoBehaviour + { + private void Awake() + { + Dependencies.Register(); + } + } +} diff --git a/BDArmory.Core/BuildingDamage.cs b/BDArmory.Core/BuildingDamage.cs new file mode 100644 index 000000000..6dcaa2cf6 --- /dev/null +++ b/BDArmory.Core/BuildingDamage.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace BDArmory.Core +{ + [KSPAddon(KSPAddon.Startup.MainMenu, false)] + public class BuildingDamage : ScenarioDestructibles + { + public override void OnAwake() + { + Debug.Log("[BDArmory]: Modifying Buildings"); + + foreach (KeyValuePair bldg in protoDestructibles) + { + DestructibleBuilding building = bldg.Value.dBuildingRefs[0]; + building.damageDecay = 600f; + building.impactMomentumThreshold *= 150; + } + } + } +} diff --git a/BDArmory.Core/Dependencies.cs b/BDArmory.Core/Dependencies.cs new file mode 100644 index 000000000..465dcfb28 --- /dev/null +++ b/BDArmory.Core/Dependencies.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; + +namespace BDArmory.Core +{ + public static class Dependencies + { + private static readonly Dictionary Systems = new Dictionary(); + + public static void Register() + { + if (!Systems.ContainsKey(typeof(T))) + { + Systems.Add(typeof(T), Activator.CreateInstance()); + } + } + + public static void Register(object obj) + { + if (obj == null) + { + throw new NullReferenceException("Registering null constant"); + } + if (!Systems.ContainsKey(typeof(T))) + { + Systems.Add(typeof(T), obj); + } + } + + public static T Get() where T : class + { + Type type = typeof(T); + Object instance; + Systems.TryGetValue(type, out instance); + + if (instance == null) + { + instance = Activator.CreateInstance(); + Systems.Add(type, instance); + } + + return instance as T; + } + + public static bool Exist() where T : class + { + return Systems.ContainsKey(typeof(T)); + } + } +} diff --git a/BDArmory.Core/Enum/DamageOperation.cs b/BDArmory.Core/Enum/DamageOperation.cs new file mode 100644 index 000000000..2809cce98 --- /dev/null +++ b/BDArmory.Core/Enum/DamageOperation.cs @@ -0,0 +1,8 @@ +namespace BDArmory.Core.Enum +{ + public enum DamageOperation + { + Set = 0, + Add = 1 + } +} diff --git a/BDArmory.Core/Events/DamageEventArgs.cs b/BDArmory.Core/Events/DamageEventArgs.cs new file mode 100644 index 000000000..7941b4770 --- /dev/null +++ b/BDArmory.Core/Events/DamageEventArgs.cs @@ -0,0 +1,15 @@ +using System; +using BDArmory.Core.Enum; + +namespace BDArmory.Core.Events +{ + [Serializable] + public class DamageEventArgs : EventArgs + { + public int VesselId { get; set; } + public int PartId { get; set; } + public float Damage { get; set; } + public float Armor { get; set; } + public DamageOperation Operation { get; set; } + } +} diff --git a/BDArmory.Core/Extension/DamageFX.cs b/BDArmory.Core/Extension/DamageFX.cs new file mode 100644 index 000000000..ea7112864 --- /dev/null +++ b/BDArmory.Core/Extension/DamageFX.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace BDArmory.Core.Extension +{ + public class DamageFX : MonoBehaviour + { + public static bool engineDamaged = false; + + public void Start() + { + } + + public void FixedUpdate() + { + if (engineDamaged) + { + float probability = Utils.BDAMath.RangedProbability(new[] { 50f, 25f, 20f, 2f }); + if (probability >= 3) + { + ModuleEngines engine = gameObject.GetComponent(); + engine.flameout = true; + engine.heatProduction *= 1.05f; + engine.maxThrust *= 0.825f; + } + } + } + + public static void SetEngineDamage(Part part) + { + ModuleEngines engine; + engine = part.GetComponent(); + engine.flameout = true; + engine.heatProduction *= 1.0125f; + engine.maxThrust *= 0.825f; + } + + public static void SetWingDamage(Part part) + { + ModuleLiftingSurface wing; + wing = part.GetComponent(); + wing.deflectionLiftCoeff *= 0.825f; + } + } +} diff --git a/BDArmory.Core/Extension/PartExtensions.cs b/BDArmory.Core/Extension/PartExtensions.cs new file mode 100644 index 000000000..7096724c3 --- /dev/null +++ b/BDArmory.Core/Extension/PartExtensions.cs @@ -0,0 +1,431 @@ +using System; +using System.Collections.Generic; +using BDArmory.Core.Services; +using BDArmory.Core.Utils; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Core.Extension +{ + public static class PartExtensions + { + public static void AddDamage(this Part p, float damage) + { + ////////////////////////////////////////////////////////// + // Basic Add Hitpoints for compatibility + ////////////////////////////////////////////////////////// + damage = (float)Math.Round(damage, 2); + + if (p.GetComponent() != null) + { + ApplyHitPoints(p.GetComponent(), damage); + } + else + { + Dependencies.Get().AddDamageToPart_svc(p, damage); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Standard Hitpoints Applied : " + damage); + } + } + + public static void AddExplosiveDamage(this Part p, + float explosiveDamage, + float caliber, + bool isMissile) + { + float damage_ = 0f; + + ////////////////////////////////////////////////////////// + // Explosive Hitpoints + ////////////////////////////////////////////////////////// + + if (isMissile) + { + damage_ = (BDArmorySettings.DMG_MULTIPLIER / 100) * BDArmorySettings.EXP_DMG_MOD_MISSILE * explosiveDamage; + } + else + { + damage_ = (BDArmorySettings.DMG_MULTIPLIER / 100) * BDArmorySettings.EXP_DMG_MOD_BALLISTIC * explosiveDamage; + } + + ////////////////////////////////////////////////////////// + // Armor Reduction factors + ////////////////////////////////////////////////////////// + + if (p.HasArmor()) + { + float armorMass_ = p.GetArmorThickness(); + float damageReduction = DamageReduction(armorMass_, damage_, isMissile, caliber); + + damage_ = damageReduction; + } + + ////////////////////////////////////////////////////////// + // Apply Hitpoints + ////////////////////////////////////////////////////////// + + if (p.GetComponent() != null) + { + ApplyHitPoints(p.GetComponent(), (float)damage_); + } + else + { + ApplyHitPoints(p, damage_); + } + } + + public static void AddBallisticDamage(this Part p, + float mass, + float caliber, + float multiplier, + float penetrationfactor, + float bulletDmgMult, + float impactVelocity) + { + ////////////////////////////////////////////////////////// + // Basic Kinetic Formula + ////////////////////////////////////////////////////////// + //Hitpoints mult for scaling in settings + //1e-4 constant for adjusting MegaJoules for gameplay + + float damage_ = ((0.5f * (mass * Mathf.Pow(impactVelocity, 2))) + * (BDArmorySettings.DMG_MULTIPLIER / 100) * bulletDmgMult + * 1e-4f * BDArmorySettings.BALLISTIC_DMG_FACTOR); + + ////////////////////////////////////////////////////////// + // Armor Reduction factors + ////////////////////////////////////////////////////////// + + if (p.HasArmor()) + { + float armorMass_ = p.GetArmorThickness(); + float damageReduction = DamageReduction(armorMass_, damage_, false, caliber, penetrationfactor); + + damage_ = damageReduction; + } + + ////////////////////////////////////////////////////////// + // Apply Hitpoints + ////////////////////////////////////////////////////////// + + if (p.GetComponent() != null) + { + ApplyHitPoints(p.GetComponent(), (float)damage_); + } + else + { + ApplyHitPoints(p, damage_, caliber, mass, mass, impactVelocity, penetrationfactor); + } + } + + /// + /// Ballistic Hitpoint Damage + /// + public static void ApplyHitPoints(Part p, float damage_, float caliber, float mass, float multiplier, float impactVelocity, float penetrationfactor) + { + ////////////////////////////////////////////////////////// + // Apply HitPoints Ballistic + ////////////////////////////////////////////////////////// + Dependencies.Get().AddDamageToPart_svc(p, damage_); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: mass: " + mass + " caliber: " + caliber + " multiplier: " + multiplier + " velocity: " + impactVelocity + " penetrationfactor: " + penetrationfactor); + Debug.Log("[BDArmory]: Ballistic Hitpoints Applied : " + Math.Round(damage_, 2)); + } + + //CheckDamageFX(p); + } + + /// + /// Explosive Hitpoint Damage + /// + public static void ApplyHitPoints(Part p, float damage) + { + ////////////////////////////////////////////////////////// + // Apply Hitpoints / Explosive + ////////////////////////////////////////////////////////// + + Dependencies.Get().AddDamageToPart_svc(p, damage); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Explosive Hitpoints Applied to " + p.name + ": " + Math.Round(damage, 2)); + + //CheckDamageFX(p); + } + + /// + /// Kerbal Hitpoint Damage + /// + public static void ApplyHitPoints(KerbalEVA kerbal, float damage) + { + ////////////////////////////////////////////////////////// + // Apply Hitpoints / Kerbal + ////////////////////////////////////////////////////////// + + Dependencies.Get().AddDamageToKerbal_svc(kerbal, damage); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Hitpoints Applied to " + kerbal.name + ": " + Math.Round(damage, 2)); + } + + public static void AddForceToPart(Rigidbody rb, Vector3 force, Vector3 position, ForceMode mode) + { + ////////////////////////////////////////////////////////// + // Add The force to part + ////////////////////////////////////////////////////////// + + rb.AddForceAtPosition(force, position, mode); + Debug.Log("[BDArmory]: Force Applied : " + Math.Round(force.magnitude, 2)); + } + + public static void Destroy(this Part p) + { + Dependencies.Get().SetDamageToPart_svc(p, -1); + } + + public static bool HasArmor(this Part p) + { + return p.GetArmorThickness() > 15f; + } + + public static bool GetFireFX(this Part p) + { + return Dependencies.Get().HasFireFX_svc(p); + } + + public static float GetFireFXTimeOut(this Part p) + { + return Dependencies.Get().GetFireFXTimeOut(p); + } + + public static float Damage(this Part p) + { + return Dependencies.Get().GetPartDamage_svc(p); + } + + public static float MaxDamage(this Part p) + { + return Dependencies.Get().GetMaxPartDamage_svc(p); + } + + public static void ReduceArmor(this Part p, double massToReduce) + { + if (!p.HasArmor()) return; + massToReduce = Math.Max(0.10, Math.Round(massToReduce, 2)); + Dependencies.Get().ReduceArmor_svc(p, (float)massToReduce); + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Armor Removed : " + massToReduce); + } + } + + public static float GetArmorThickness(this Part p) + { + if (p == null) return 0f; + return Dependencies.Get().GetPartArmor_svc(p); + } + + public static float GetArmorPercentage(this Part p) + { + if (p == null) return 0; + float armor_ = Dependencies.Get().GetPartArmor_svc(p); + float maxArmor_ = Dependencies.Get().GetMaxArmor_svc(p); + + return armor_ / maxArmor_; + } + + public static float GetDamagePercentatge(this Part p) + { + if (p == null) return 0; + + float damage_ = p.Damage(); + float maxDamage_ = p.MaxDamage(); + + return damage_ / maxDamage_; + } + + public static void RefreshAssociatedWindows(this Part part) + { + //Thanks FlowerChild + //refreshes part action window + + //IEnumerator window = UnityEngine.Object.FindObjectsOfType(typeof(UIPartActionWindow)).Cast().GetEnumerator(); + //while (window.MoveNext()) + //{ + // if (window.Current == null) continue; + // if (window.Current.part == part) + // { + // window.Current.displayDirty = true; + // } + //} + //window.Dispose(); + + MonoUtilities.RefreshContextWindows(part); + } + + public static bool IsMissile(this Part part) + { + return part.Modules.Contains("MissileBase") || part.Modules.Contains("MissileLauncher") || + part.Modules.Contains("BDModularGuidance"); + } + + public static float GetArea(this Part part, bool isprefab = false, Part prefab = null) + { + var size = part.GetSize(); + float sfcAreaCalc = 2f * (size.x * size.y) + 2f * (size.y * size.z) + 2f * (size.x * size.z); + + return sfcAreaCalc; + } + + public static float GetAverageBoundSize(this Part part) + { + var size = part.GetSize(); + + return (size.x + size.y + size.z) / 3f; + } + + public static float GetVolume(this Part part) + { + var size = part.GetSize(); + var volume = size.x * size.y * size.z; + return volume; + } + + public static Vector3 GetSize(this Part part) + { + var size = part.GetComponentInChildren().mesh.bounds.size; + + if (part.name.Contains("B9.Aero.Wing.Procedural")) + { + size = size * 0.1f; + } + + float scaleMultiplier = 1f; + if (part.Modules.Contains("TweakScale")) + { + var tweakScaleModule = part.Modules["TweakScale"]; + scaleMultiplier = tweakScaleModule.Fields["currentScale"].GetValue(tweakScaleModule) / + tweakScaleModule.Fields["defaultScale"].GetValue(tweakScaleModule); + } + + return size * scaleMultiplier; + } + + public static bool IsAero(this Part part) + { + return part.Modules.Contains("ModuleControlSurface") || + part.Modules.Contains("ModuleLiftingSurface"); + } + + public static string GetExplodeMode(this Part part) + { + return Dependencies.Get().GetExplodeMode_svc(part); + } + + public static bool IgnoreDecal(this Part part) + { + if ( + part.Modules.Contains("FSplanePropellerSpinner") || + part.Modules.Contains("ModuleWheelBase") || + part.Modules.Contains("KSPWheelBase") || + part.gameObject.GetComponentUpwards() || + part.Modules.Contains("ModuleDCKShields") || + part.Modules.Contains("ModuleShieldGenerator") + ) + { + return true; + } + else + { + return false; + } + } + + public static bool HasFuel(this Part part) + { + bool hasFuel = false; + IEnumerator resources = part.Resources.GetEnumerator(); + while (resources.MoveNext()) + { + if (resources.Current == null) continue; + switch (resources.Current.resourceName) + { + case "LiquidFuel": + if (resources.Current.amount > 1d) hasFuel = true; + break; + } + } + return hasFuel; + } + + public static float DamageReduction(float armor, float damage, bool isMissile, float caliber = 0, float penetrationfactor = 0) + { + float _damageReduction; + + if (isMissile) + { + if (BDAMath.Between(armor, 100f, 200f)) + { + damage *= 0.95f; + } + else if (BDAMath.Between(armor, 200f, 400f)) + { + damage *= 0.875f; + } + else if (BDAMath.Between(armor, 400f, 500f)) + { + damage *= 0.80f; + } + } + + if (!isMissile && !(penetrationfactor >= 1f)) + { + //if (BDAMath.Between(armor, 100f, 200f)) + //{ + // damage *= 0.300f; + //} + //else if (BDAMath.Between(armor, 200f, 400f)) + //{ + // damage *= 0.250f; + //} + //else if (BDAMath.Between(armor, 400f, 500f)) + //{ + // damage *= 0.200f; + //} + + //y=(98.34817*x)/(97.85935+x) + + _damageReduction = (113 * armor) / (154 + armor); + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Damage Before Reduction : " + Math.Round(damage, 2) / 100); + Debug.Log("[BDArmory]: Damage Reduction : " + Math.Round(_damageReduction, 2) / 100); + Debug.Log("[BDArmory]: Damage After Armor : " + Math.Round(damage *= (_damageReduction / 100f))); + } + + damage *= (_damageReduction / 100f); + } + + return damage; + } + + public static void CheckDamageFX(Part part) + { + if (part.GetComponent() != null && part.GetDamagePercentatge() <= 0.35f) + { + part.gameObject.AddOrGetComponent(); + DamageFX.engineDamaged = true; + } + + if (part.GetComponent() != null && part.GetDamagePercentatge() <= 0.35f) + { + //part.gameObject.AddOrGetComponent(); + } + } + + public static Vector3 GetBoundsSize(Part part) + { + return PartGeometryUtil.MergeBounds(part.GetRendererBounds(), part.transform).size; + } + } +} diff --git a/BDArmory.Core/Extension/VesselExtensions.cs b/BDArmory.Core/Extension/VesselExtensions.cs new file mode 100644 index 000000000..3eea61531 --- /dev/null +++ b/BDArmory.Core/Extension/VesselExtensions.cs @@ -0,0 +1,73 @@ +using System; +using UnityEngine; + +namespace BDArmory.Core.Extension +{ + public static class VesselExtensions + { + public static bool InOrbit(this Vessel v) + { + try + { + return !v.LandedOrSplashed && + (v.situation == Vessel.Situations.ORBITING || + v.situation == Vessel.Situations.SUB_ORBITAL || + v.situation == Vessel.Situations.ESCAPING); + } + catch + { + return false; + } + } + + public static bool InVacuum(this Vessel v) + { + return v.atmDensity <= 0.001f; + } + + public static Vector3d Velocity(this Vessel v) + { + try + { + if (!v.InOrbit()) + { + return v.srf_velocity; + } + else + { + return v.obt_velocity; + } + } + catch + { + //return v.srf_velocity; + return new Vector3d(0, 0, 0); + } + } + + public static double GetFutureAltitude(this Vessel vessel, float predictionTime = 10) + { + Vector3 futurePosition = vessel.CoM + vessel.Velocity() * predictionTime + + 0.5f * vessel.acceleration_immediate * Mathf.Pow(predictionTime, 2); + + return GetRadarAltitudeAtPos(futurePosition); + } + + public static Vector3 GetFuturePosition (this Vessel vessel, float predictionTime = 10) + { + return vessel.CoM + vessel.Velocity() * predictionTime + 0.5f * vessel.acceleration_immediate * Math.Pow(predictionTime, 2); + } + + public static float GetRadarAltitudeAtPos(Vector3 position) + { + double latitudeAtPos = FlightGlobals.currentMainBody.GetLatitude(position); + double longitudeAtPos = FlightGlobals.currentMainBody.GetLongitude(position); + + float radarAlt = Mathf.Clamp( + (float)(FlightGlobals.currentMainBody.GetAltitude(position) - + FlightGlobals.currentMainBody.TerrainAltitude(latitudeAtPos, longitudeAtPos)), 0, + (float)FlightGlobals.currentMainBody.GetAltitude(position)); + return radarAlt; + } + } +} diff --git a/BDArmory.Core/Interface/INotificableService.cs b/BDArmory.Core/Interface/INotificableService.cs new file mode 100644 index 000000000..4a2724b80 --- /dev/null +++ b/BDArmory.Core/Interface/INotificableService.cs @@ -0,0 +1,11 @@ +using System; + +namespace BDArmory.Core.Interface +{ + public interface INotificableService where T : EventArgs + { + event EventHandler OnActionExecuted; + + void PublishEvent(T t); + } +} diff --git a/BDArmory.Core/Module/HitpointTracker.cs b/BDArmory.Core/Module/HitpointTracker.cs new file mode 100644 index 000000000..10a0b7162 --- /dev/null +++ b/BDArmory.Core/Module/HitpointTracker.cs @@ -0,0 +1,280 @@ +using BDArmory.Core.Extension; +using UnityEngine; + +namespace BDArmory.Core.Module +{ + public class HitpointTracker : PartModule + { + #region KSP Fields + + [KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_Hitpoints"),//Hitpoints + UI_ProgressBar(affectSymCounterparts = UI_Scene.None, controlEnabled = false, scene = UI_Scene.All, maxValue = 100000, minValue = 0, requireFullControl = false)] + public float Hitpoints; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_ArmorThickness"),//Armor Thickness + UI_FloatRange(minValue = 1f, maxValue = 500f, stepIncrement = 5f, scene = UI_Scene.All)] + public float Armor = 10f; + + [KSPField(isPersistant = true)] + public float maxHitPoints = 0f; + + [KSPField(isPersistant = true)] + public float ArmorThickness = 0f; + + [KSPField(isPersistant = true)] + public bool ArmorSet; + + [KSPField(isPersistant = true)] + public string ExplodeMode = "Never"; + + [KSPField(isPersistant = true)] + public bool FireFX = true; + + [KSPField(isPersistant = true)] + public float FireFXLifeTimeInSeconds = 5f; + + #endregion KSP Fields + + private readonly float hitpointMultiplier = BDArmorySettings.HITPOINT_MULTIPLIER; + + private float previousHitpoints; + private bool _updateHitpoints = false; + private bool _forceUpdateHitpointsUI = false; + private const int HpRounding = 100; + + public override void OnLoad(ConfigNode node) + { + base.OnLoad(node); + + if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) return; + + if (part.partInfo == null) + { + // Loading of the prefab from the part config + _updateHitpoints = true; + } + else + { + // Loading of the part from a saved craft + if (HighLogic.LoadedSceneIsEditor) + { + _updateHitpoints = true; + } + else + enabled = false; + } + } + + public void SetupPrefab() + { + if (part != null) + { + var maxHitPoints_ = CalculateTotalHitpoints(); + + if (!_forceUpdateHitpointsUI && previousHitpoints == maxHitPoints_) return; + + //Add Hitpoints + UI_ProgressBar damageFieldFlight = (UI_ProgressBar)Fields["Hitpoints"].uiControlFlight; + damageFieldFlight.maxValue = maxHitPoints_; + damageFieldFlight.minValue = 0f; + + UI_ProgressBar damageFieldEditor = (UI_ProgressBar)Fields["Hitpoints"].uiControlEditor; + damageFieldEditor.maxValue = maxHitPoints_; + damageFieldEditor.minValue = 0f; + + Hitpoints = maxHitPoints_; + + //Add Armor + UI_FloatRange armorFieldFlight = (UI_FloatRange)Fields["Armor"].uiControlFlight; + armorFieldFlight.maxValue = 500f; + armorFieldFlight.minValue = 10; + + UI_FloatRange armorFieldEditor = (UI_FloatRange)Fields["Armor"].uiControlEditor; + armorFieldEditor.maxValue = 500f; + armorFieldEditor.minValue = 10f; + part.RefreshAssociatedWindows(); + + if (!ArmorSet) overrideArmorSetFromConfig(); + + previousHitpoints = maxHitPoints_; + } + else + { + Debug.Log("[BDArmory]: HitpointTracker::OnStart part is null"); + } + } + + public override void OnStart(StartState state) + { + isEnabled = true; + + if (part != null) _updateHitpoints = true; + + if (HighLogic.LoadedSceneIsFlight) + { + UI_FloatRange armorField = (UI_FloatRange)Fields["Armor"].uiControlFlight; + //Once started the max value of the field should be the initial one + armorField.maxValue = Armor; + part.RefreshAssociatedWindows(); + } + GameEvents.onEditorShipModified.Add(ShipModified); + } + + private void OnDestroy() + { + GameEvents.onEditorShipModified.Remove(ShipModified); + } + + public void ShipModified(ShipConstruct data) + { + _updateHitpoints = true; + } + + public override void OnUpdate() + { + RefreshHitPoints(); + } + + public void Update() + { + RefreshHitPoints(); + } + + private void RefreshHitPoints() + { + if (_updateHitpoints) + { + SetupPrefab(); + _updateHitpoints = false; + _forceUpdateHitpointsUI = false; + } + } + + #region Hitpoints Functions + + public float CalculateTotalHitpoints() + { + float hitpoints; + + if (!part.IsMissile()) + { + var averageSize = part.GetAverageBoundSize(); + var sphereRadius = averageSize * 0.5f; + var sphereSurface = 4 * Mathf.PI * sphereRadius * sphereRadius; + var structuralVolume = sphereSurface * 0.1f; + + var density = (part.mass * 1000f) / structuralVolume; + density = Mathf.Clamp(density, 1000, 10000); + //Debug.Log("[BDArmory]: Hitpoint Calc" + part.name + " | structuralVolume : " + structuralVolume); + //Debug.Log("[BDArmory]: Hitpoint Calc"+part.name+" | Density : " + density); + + var structuralMass = density * structuralVolume; + //Debug.Log("[BDArmory]: Hitpoint Calc" + part.name + " | structuralMass : " + structuralMass); + //3. final calculations + hitpoints = structuralMass * hitpointMultiplier * 0.33f; + + if (hitpoints > 10 * part.mass * 1000f || hitpoints < 0.1f * part.mass * 1000f) + { + Debug.Log($"[BDArmory]: HitpointTracker::Clamping hitpoints for part {part.name}"); + hitpoints = hitpointMultiplier * part.mass * 333f; + } + + hitpoints = Mathf.Round(hitpoints / HpRounding) * HpRounding; + if (hitpoints <= 0) hitpoints = HpRounding; + } + else + { + hitpoints = 5; + Armor = 2; + } + + //override based on part configuration for custom parts + if (maxHitPoints != 0) + { + hitpoints = maxHitPoints; + } + + if (hitpoints <= 0) hitpoints = HpRounding; + return hitpoints; + } + + public void DestroyPart() + { + if (part.mass <= 2f) part.explosionPotential *= 0.85f; + + PartExploderSystem.AddPartToExplode(part); + } + + public float GetMaxArmor() + { + UI_FloatRange armorField = (UI_FloatRange)Fields["Armor"].uiControlEditor; + return armorField.maxValue; + } + + public float GetMaxHitpoints() + { + UI_ProgressBar hitpointField = (UI_ProgressBar)Fields["Hitpoints"].uiControlEditor; + return hitpointField.maxValue; + } + + public bool GetFireFX() + { + return FireFX; + } + + public void SetDamage(float partdamage) + { + Hitpoints -= partdamage; + + if (Hitpoints <= 0) + { + DestroyPart(); + } + } + + public void AddDamage(float partdamage) + { + if (part.name == "Weapon Manager" || part.name == "BDModulePilotAI") return; + + partdamage = Mathf.Max(partdamage, 0.01f) * -1; + Hitpoints += partdamage; + + if (Hitpoints <= 0) + { + DestroyPart(); + } + } + + public void AddDamageToKerbal(KerbalEVA kerbal, float damage) + { + damage = Mathf.Max(damage, 0.01f) * -1; + Hitpoints += damage; + + if (Hitpoints <= 0) + { + // oh the humanity! + PartExploderSystem.AddPartToExplode(kerbal.part); + } + } + + public void ReduceArmor(float massToReduce) + { + Armor -= massToReduce; + if (Armor < 0) + { + Armor = 0; + } + } + + public void overrideArmorSetFromConfig(float thickness = 0) + { + ArmorSet = true; + if (ArmorThickness != 0) + { + Armor = ArmorThickness; + } + } + + #endregion Hitpoints Functions + } +} diff --git a/BDArmory.Core/PartExploderSystem.cs b/BDArmory.Core/PartExploderSystem.cs new file mode 100644 index 000000000..d30f44c24 --- /dev/null +++ b/BDArmory.Core/PartExploderSystem.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace BDArmory.Core +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class PartExploderSystem : MonoBehaviour + { + private static readonly Queue ExplodingPartsQueue = new Queue(); + + public static void AddPartToExplode(Part p) + { + if (p != null && !ExplodingPartsQueue.Contains(p)) + { + ExplodingPartsQueue.Enqueue(p); + } + } + + private void OnDestroy() + { + ExplodingPartsQueue.Clear(); + } + + public void Update() + { + var timeNow = Time.time; + if (ExplodingPartsQueue.Count == 0) return; + + do + { + Part part = ExplodingPartsQueue.Dequeue(); + + if (part != null) + { + part.explode(); + } + } while (Time.time - timeNow < Time.deltaTime && ExplodingPartsQueue.Count > 0); + } + } +} diff --git a/BDArmory.Core/PerformanceLogger.cs b/BDArmory.Core/PerformanceLogger.cs new file mode 100644 index 000000000..e82bdb26a --- /dev/null +++ b/BDArmory.Core/PerformanceLogger.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace BDArmory.Core +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class PerformanceLogger : MonoBehaviour, IDisposable + { + private const string FileName = "BDArmory_PerformanceLog.txt"; + + private static readonly Dictionary PerformanceEntries = + new Dictionary(); + + private readonly string _id; + + private readonly Stopwatch _stopwatch; + + public PerformanceLogger(string id) + { + if (!BDArmorySettings.PERFORMANCE_LOGGING) + return; + + _stopwatch = Stopwatch.StartNew(); + _id = id; + } + + public void Dispose() + { + if (!BDArmorySettings.PERFORMANCE_LOGGING) + return; + _stopwatch.Stop(); + + if (PerformanceEntries.ContainsKey(_id)) + UpdatePerformanceRecord(); + else + CreatePerformanceRecord(); + } + + private void OnDestroy() + { + if (PerformanceEntries.Count == 0) + return; + + Debug.Log("PerformanceLogger.OnDestroy"); + + var sb = new StringBuilder(); + foreach (var performanceEntry in PerformanceEntries.OrderByDescending(x => x.Value.TotalTicks)) + { + sb.AppendFormat("{0:yyyy/MM/dd HH:mm:ss.ff} - Performance Entry Id: {1} => {2}", DateTime.Now, + performanceEntry.Key, performanceEntry.Value); + sb.AppendLine(); + } + + File.AppendAllText(GetFilePath(), sb.ToString()); + + PerformanceEntries.Clear(); + } + + private string GetFilePath() + { + return Path.Combine(Path.Combine(Application.dataPath, ".."), + FileName); + } + + private void CreatePerformanceRecord() + { + PerformanceEntries.Add(_id, new PerformanceData + { + Calls = 1, + TotalTicks = _stopwatch.ElapsedTicks, + MaxTick = _stopwatch.ElapsedTicks, + MinTick = _stopwatch.ElapsedTicks + }); + } + + private void UpdatePerformanceRecord() + { + var performanceData = PerformanceEntries[_id]; + performanceData.Calls += 1; + performanceData.TotalTicks += _stopwatch.ElapsedTicks; + + performanceData.MaxTick = _stopwatch.ElapsedTicks > performanceData.MaxTick + ? _stopwatch.ElapsedTicks + : performanceData.MaxTick; + + performanceData.MinTick = _stopwatch.ElapsedTicks < performanceData.MinTick + ? _stopwatch.ElapsedTicks + : performanceData.MinTick; + } + } + + internal class PerformanceData + { + public int Calls { get; set; } + public long TotalTicks { get; set; } + public float AverageTicks => (float)Math.Round(TotalTicks / (float)Calls, 1); + + public long MaxTick { get; set; } + public long MinTick { get; set; } + + public override string ToString() + { + var sb = new StringBuilder(); + sb.AppendFormat("Average ticks {0} | Max ticks {1} | Min ticks {2} | Total ticks {3} | Calls {4}", + AverageTicks, MaxTick, MinTick, TotalTicks, Calls); + + return sb.ToString(); + } + } +} diff --git a/BDArmory.Core/Properties/AssemblyInfo.cs b/BDArmory.Core/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f87e5a556 --- /dev/null +++ b/BDArmory.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BDArmory.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a6f1753e-9570-4c40-af72-a179890582e5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.3.4.0")] +[assembly: AssemblyFileVersion("1.3.4.0")] +[assembly: KSPAssembly("BDArmory.Core", 1, 0)] diff --git a/BDArmory.Core/Services/DamageService.cs b/BDArmory.Core/Services/DamageService.cs new file mode 100644 index 000000000..622e7151a --- /dev/null +++ b/BDArmory.Core/Services/DamageService.cs @@ -0,0 +1,31 @@ +using BDArmory.Core.Events; + +namespace BDArmory.Core.Services +{ + public abstract class DamageService : NotificableService + { + public abstract void ReduceArmor_svc(Part p, float armorMass); + + public abstract void SetDamageToPart_svc(Part p, float damage); + + public abstract void AddDamageToPart_svc(Part p, float damage); + + public abstract void AddDamageToKerbal_svc(KerbalEVA kerbal, float damage); + + public abstract float GetPartDamage_svc(Part p); + + public abstract float GetPartArmor_svc(Part p); + + public abstract float GetMaxPartDamage_svc(Part p); + + public abstract float GetMaxArmor_svc(Part p); + + public abstract void DestroyPart_svc(Part p); + + public abstract string GetExplodeMode_svc(Part p); + + public abstract bool HasFireFX_svc(Part p); + + public abstract float GetFireFXTimeOut(Part p); + } +} diff --git a/BDArmory.Core/Services/ModuleDamageService.cs b/BDArmory.Core/Services/ModuleDamageService.cs new file mode 100644 index 000000000..b493b82fa --- /dev/null +++ b/BDArmory.Core/Services/ModuleDamageService.cs @@ -0,0 +1,114 @@ +using BDArmory.Core.Enum; +using BDArmory.Core.Events; +using BDArmory.Core.Module; +using UnityEngine; + +namespace BDArmory.Core.Services +{ + internal class ModuleDamageService : DamageService + { + public override void ReduceArmor_svc(Part p, float armorMass) + { + var damageModule = p.Modules.GetModule(); + + damageModule.ReduceArmor(armorMass); + + PublishEvent(new DamageEventArgs() + { + VesselId = p.vessel.GetInstanceID(), + PartId = p.GetInstanceID(), + Armor = armorMass, + Operation = DamageOperation.Set + }); + } + + public override void SetDamageToPart_svc(Part p, float PartDamage) + { + var damageModule = p.Modules.GetModule(); + + damageModule.SetDamage(PartDamage); + + PublishEvent(new DamageEventArgs() + { + VesselId = p.vessel.GetInstanceID(), + PartId = p.GetInstanceID(), + Damage = PartDamage, + Operation = DamageOperation.Set + }); + } + + public override void AddDamageToPart_svc(Part p, float PartDamage) + { + var damageModule = p.Modules.GetModule(); + + damageModule.AddDamage(PartDamage); + + PublishEvent(new DamageEventArgs() + { + VesselId = p.vessel.GetInstanceID(), + PartId = p.GetInstanceID(), + Damage = PartDamage, + Operation = DamageOperation.Add + }); + } + + public override void AddDamageToKerbal_svc(KerbalEVA kerbal, float damage) + { + var damageModule = kerbal.part.Modules.GetModule(); + + damageModule.AddDamageToKerbal(kerbal, damage); + + PublishEvent(new DamageEventArgs() + { + VesselId = kerbal.part.vessel.GetInstanceID(), + PartId = kerbal.part.GetInstanceID(), + Damage = damage, + Operation = DamageOperation.Add + }); + } + + public override float GetPartDamage_svc(Part p) + { + return p.Modules.GetModule().Hitpoints; + } + + public override float GetPartArmor_svc(Part p) + { + float armor_ = Mathf.Max(1, p.Modules.GetModule().Armor); + return armor_; + } + + public override float GetMaxPartDamage_svc(Part p) + { + return p.Modules.GetModule().GetMaxHitpoints(); + } + + public override float GetMaxArmor_svc(Part p) + { + return p.Modules.GetModule().GetMaxArmor(); + } + + public override void DestroyPart_svc(Part p) + { + p.Modules.GetModule().DestroyPart(); + } + + public override string GetExplodeMode_svc(Part p) + { + return p.Modules.GetModule().ExplodeMode; + } + + public override bool HasFireFX_svc(Part p) + { + if (p == null) return false; + if (p.Modules.GetModule() == null) return false; + + return p.Modules.GetModule().GetFireFX(); + } + + public override float GetFireFXTimeOut(Part p) + { + return p.Modules.GetModule().FireFXLifeTimeInSeconds; + } + } +} diff --git a/BDArmory.Core/Services/NotificableService.cs b/BDArmory.Core/Services/NotificableService.cs new file mode 100644 index 000000000..cdc24e0cb --- /dev/null +++ b/BDArmory.Core/Services/NotificableService.cs @@ -0,0 +1,15 @@ +using System; +using BDArmory.Core.Interface; + +namespace BDArmory.Core.Services +{ + public abstract class NotificableService : INotificableService where T : EventArgs + { + public event EventHandler OnActionExecuted; + + public void PublishEvent(T t) + { + OnActionExecuted?.Invoke(this, t); + } + } +} diff --git a/BDArmory.Core/Utils/BDAMath.cs b/BDArmory.Core/Utils/BDAMath.cs new file mode 100644 index 000000000..b3b764a5a --- /dev/null +++ b/BDArmory.Core/Utils/BDAMath.cs @@ -0,0 +1,36 @@ +namespace BDArmory.Core.Utils +{ + public static class BDAMath + { + public static float RangedProbability(float[] probs) + { + float total = 0; + foreach (float elem in probs) + { + total += elem; + } + + float randomPoint = UnityEngine.Random.value * total; + + for (int i = 0; i < probs.Length; i++) + { + if (randomPoint < probs[i]) + { + return i; + } + else + { + randomPoint -= probs[i]; + } + } + return probs.Length - 1; + } + + public static bool Between(this float num, float lower, float upper, bool inclusive = true) + { + return inclusive + ? lower <= num && num <= upper + : lower < num && num < upper; + } + } +} diff --git a/BDArmory.Core/Utils/BlastPhysicsUtils.cs b/BDArmory.Core/Utils/BlastPhysicsUtils.cs new file mode 100644 index 000000000..3e38746b4 --- /dev/null +++ b/BDArmory.Core/Utils/BlastPhysicsUtils.cs @@ -0,0 +1,153 @@ +using System; +using BDArmory.Core.Extension; +using UnityEngine; + +namespace BDArmory.Core.Utils +{ + public static class BlastPhysicsUtils + { + // This values represent percentage of the blast radius where we consider that the damage happens. + + public static BlastInfo CalculatePartBlastEffects(Part part, float distanceToHit, double vesselMass, float explosiveMass, float range) + { + float clampedMinDistanceToHit = ClampRange(explosiveMass, distanceToHit); + + var minPressureDistance = distanceToHit + part.GetAverageBoundSize(); + + double minPressurePerMs = 0; + + if (minPressureDistance <= range) + { + float clampedMaxDistanceToHit = ClampRange(explosiveMass, minPressureDistance); + double maxScaledDistance = CalculateScaledDistance(explosiveMass, clampedMaxDistanceToHit); + minPressurePerMs = CalculateIncidentImpulse(maxScaledDistance, explosiveMass); + } + + double minScaledDistance = CalculateScaledDistance(explosiveMass, clampedMinDistanceToHit); + double maxPressurePerMs = CalculateIncidentImpulse(minScaledDistance, explosiveMass); + + double totalDamage = (maxPressurePerMs + minPressurePerMs);// * 2 / 2 ; + + float effectivePartArea = CalculateEffectiveBlastAreaToPart(range, part); + + float positivePhase = 5; + + double maxforce = CalculateForce(maxPressurePerMs, effectivePartArea, positivePhase); + double minforce = CalculateForce(minPressurePerMs, effectivePartArea, positivePhase); + + double force = (maxforce + minforce) / 2f; + + float acceleration = (float)(force / vesselMass); + + // Calculation of damage + + float finalDamage = (float)totalDamage; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log( + "[BDArmory]: Blast Debug data: {" + part.name + "}, " + + " clampedMinDistanceToHit: {" + clampedMinDistanceToHit + "}," + + " minPressureDistance: {" + minPressureDistance + "}," + + " minScaledDistance: {" + minScaledDistance + "}," + + " minPressurePerMs: {" + minPressurePerMs + "}," + + " maxPressurePerMs: {" + maxPressurePerMs + "}," + + " totalDamage: {" + totalDamage + "}," + + " finalDamage: {" + finalDamage + "},"); + } + + return new BlastInfo() { TotalPressure = maxPressurePerMs, EffectivePartArea = effectivePartArea, PositivePhaseDuration = positivePhase, VelocityChange = acceleration, Damage = finalDamage }; + } + + private static float CalculateEffectiveBlastAreaToPart(float range, Part part) + { + float circularArea = Mathf.PI * range * range; + + return Mathf.Clamp(circularArea, 0f, part.GetArea() * 0.40f); + } + + private static double CalculateScaledDistance(float explosiveCharge, float distanceToHit) + { + return (distanceToHit / Math.Pow(explosiveCharge, 1f / 3f)); + } + + private static float ClampRange(float explosiveCharge, float distanceToHit) + { + float cubeRootOfChargeWeight = (float)Math.Pow(explosiveCharge, 1f / 3f); + + return Mathf.Clamp(distanceToHit, 0.0674f * cubeRootOfChargeWeight, 40f * cubeRootOfChargeWeight); + } + + private static double CalculateIncidentImpulse(double scaledDistance, float explosiveCharge) + { + double t = Math.Log(scaledDistance) / Math.Log(10); + double cubeRootOfChargeWeight = Math.Pow(explosiveCharge, 0.3333333); + double ii = 0; + if (scaledDistance <= 0.955) + { //NATO version + double U = 2.06761908721 + 3.0760329666 * t; + ii = 2.52455620925 - 0.502992763686 * U + + 0.171335645235 * Math.Pow(U, 2) + + 0.0450176963051 * Math.Pow(U, 3) - + 0.0118964626402 * Math.Pow(U, 4); + } + else if (scaledDistance > 0.955) + { //version from ??? + var U = -1.94708846747 + 2.40697745406 * t; + ii = 1.67281645863 - 0.384519026965 * U - + 0.0260816706301 * Math.Pow(U, 2) + + 0.00595798753822 * Math.Pow(U, 3) + + 0.014544526107 * Math.Pow(U, 4) - + 0.00663289334734 * Math.Pow(U, 5) - + 0.00284189327204 * Math.Pow(U, 6) + + 0.0013644816227 * Math.Pow(U, 7); + } + + ii = Math.Pow(10, ii); + ii = ii * cubeRootOfChargeWeight; + return ii; + } + + /// + /// Calculate newtons from the pressure in kPa and the surface on Square meters + /// + /// kPa + /// m2 + /// + private static double CalculateForce(double pressure, float surface, double timeInMs) + { + return pressure * 1000f * surface * (timeInMs / 1000f); + } + + /// + /// Method based on Hopkinson-Cranz Scaling Law + /// Z value of 14.8 + /// + /// tnt equivales mass in kg + /// explosive range in meters + public static float CalculateBlastRange(double tntMass) + { + return (float)(14.8f * Math.Pow(tntMass, 1 / 3f)); + } + + /// + /// Method based on Hopkinson-Cranz Scaling Law + /// Z value of 14.8 + /// + /// expected range in meters + /// explosive range in meters + public static float CalculateExplosiveMass(float range) + { + return (float)Math.Pow((range / 14.8f), 3); + } + } + + public struct BlastInfo + { + public float VelocityChange { get; set; } + public float EffectivePartArea { get; set; } + public float Damage { get; set; } + public double TotalPressure { get; set; } + public double PositivePhaseDuration { get; set; } + } +} diff --git a/BDArmory.Core/Utils/BulletPhysics.cs b/BDArmory.Core/Utils/BulletPhysics.cs new file mode 100644 index 000000000..f8e7f3ed8 --- /dev/null +++ b/BDArmory.Core/Utils/BulletPhysics.cs @@ -0,0 +1,39 @@ +using UnityEngine; + +namespace BDArmory.Core.Utils +{ + public class BulletPhysics : MonoBehaviour + { + public static Vector3 CalculateDrag(Vector3 velocity, float bulletMass, float caliber) + { + //F_drag = k * v^2 = m * a + //k = 0.5 * C_d * rho * A + + //float m = 0.2f; // kg + //float C_d = 0.295f; + //float A = Mathf.PI * 0.05f * 0.05f; // m^2 + float rho = 1.225f; // kg/m3 + + //float k = 0.5f * C_d * rho * A; + + //float vSqr = velocityVec.sqrMagnitude; + + //float aDrag = (k * vSqr) / m; + + //Has to be in a direction opposite of the bullet's velocity vector + //Vector3 dragVec = aDrag * velocityVec.normalized * -1f; + + /////////////////////////////////////////////////////// + float bulletDragArea = Mathf.PI * Mathf.Pow(caliber / 2f, 2f); + float bulletBallisticCoefficient = ((bulletMass * 1000) / (bulletDragArea * 0.295f)); + + float k = 0.5f * bulletBallisticCoefficient * rho * bulletDragArea; + float vSqr = velocity.sqrMagnitude; + float aDrag = (k * vSqr) / bulletMass; + + Vector3 dragVec = aDrag * velocity.normalized * -1f; + + return dragVec; + } + } +} diff --git a/BDArmory.Core/Utils/DebugUtils.cs b/BDArmory.Core/Utils/DebugUtils.cs new file mode 100644 index 000000000..9c051be57 --- /dev/null +++ b/BDArmory.Core/Utils/DebugUtils.cs @@ -0,0 +1,17 @@ +namespace BDArmory.Core.Utils +{ + internal class DebugUtils + { + private static readonly ScreenMessage ScreenMessage = new ScreenMessage("", 2, ScreenMessageStyle.LOWER_CENTER); + + public static void DisplayDebugMessage(string message) + { + //TODO: Pending of future refactor of BDArmory settings +#if DEBUG + ScreenMessages.RemoveMessage(ScreenMessage); + ScreenMessage.message = message; + ScreenMessages.PostScreenMessage(ScreenMessage); +#endif + } + } +} diff --git a/BDArmory.Core/Utils/LayerMask.cs b/BDArmory.Core/Utils/LayerMask.cs new file mode 100644 index 000000000..5d0a654cd --- /dev/null +++ b/BDArmory.Core/Utils/LayerMask.cs @@ -0,0 +1,26 @@ +namespace BDArmory.Core.Utils +{ + internal class LayerMask + { + public static int CreateLayerMask(bool aExclude, params int[] aLayers) + { + int v = 0; + foreach (var L in aLayers) + v |= 1 << L; + if (aExclude) + v = ~v; + return v; + } + + public static int ToLayer(int bitmask) + { + int result = bitmask > 0 ? 0 : 31; + while (bitmask > 1) + { + bitmask = bitmask >> 1; + result++; + } + return result; + } + } +} diff --git a/BDArmory/.ksplocalizer.settings b/BDArmory/.ksplocalizer.settings new file mode 100644 index 000000000..86a2881a6 --- /dev/null +++ b/BDArmory/.ksplocalizer.settings @@ -0,0 +1,11 @@ + + + #autoLOC + bda + ProjectBased + 1000017 + D:\KSP\Mods\PJS\Git\Source\BDArmory\BDArmory\Distribution\GameData\BDArmory\Localization\BDArmory.cfg + en-us,es-es,ja,ru,zh-cn + false + refactor_{LANGCODE}.cfg + \ No newline at end of file diff --git a/BDArmory/.ksplocalizer.settings.user b/BDArmory/.ksplocalizer.settings.user new file mode 100644 index 000000000..2162598d0 --- /dev/null +++ b/BDArmory/.ksplocalizer.settings.user @@ -0,0 +1,4 @@ + + + 6000000 + \ No newline at end of file diff --git a/BDArmory/BDArmory.csproj b/BDArmory/BDArmory.csproj new file mode 100644 index 000000000..8b58eb79c --- /dev/null +++ b/BDArmory/BDArmory.csproj @@ -0,0 +1,722 @@ + + + + Debug + AnyCPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35} + Library + BDArmory + BDArmory + v4.7.2 + + + + + + True + full + False + bin\Debug + DEBUG; + prompt + 4 + true + x86 + False + + + none + true + bin\Release + prompt + 4 + x86 + False + + + true + bin\Debug\ + TRACE;DEBUG;ENABLE_PROFILER + portable + AnyCPU + prompt + MinimumRecommendedRules.ruleset + default + false + + + bin\Release\ + AnyCPU + prompt + BasicCorrectnessRules.ruleset + true + false + false + + + + + False + ..\..\_LocalDev\KSPRefs\Assembly-CSharp.dll + + + False + ..\..\_LocalDev\KSPRefs\KSPAssets.dll + + + + + False + ..\..\_LocalDev\KSPRefs\UnityEngine.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.AnimationModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.AssetBundleModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.AudioModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.CoreModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.ImageConversionModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.IMGUIModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.InputLegacyModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.InputModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.JSONSerializeModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.ParticleSystemModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.PhysicsModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.TextCoreModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.TextRenderingModule.dll + + + False + ..\..\_LocalDev\KSPRefs\UnityEngine.UI.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.UIElementsModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.UIModule.dll + + + ..\..\_LocalDev\KSPRefs\UnityEngine.UnityWebRequestWWWModule.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {A6F1753E-9570-4C40-AF72-A179890582E5} + BDArmory.Core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @echo $(Targetname) +SET ModName=BDArmory + +rem this step strips the solutionName from the git path to give us the root folder for locating the LocalDev Folder +rem the echo commands are commented. used for testing of the desired path. +set GIT_PATH=$(SolutionDir) +rem @echo %25GIT_PATH%25 +set GIT_PATH=%25GIT_PATH:BDArmory\=%25 +rem @echo %25GIT_PATH%25 + +@echo ... +@echo set lpath vars from "%25GIT_PATH%25_LocalDev\LocalDev" storage... +set /p KSP_DIR=<"%25GIT_PATH%25_LocalDev\ksp_dir.txt" +set /p PDB2MDB_EXE=<"%25GIT_PATH%25_LocalDev\pdb2mdb_exe.txt" +set /p ZA_DIR=<"%25GIT_PATH%25_LocalDev\7za_dir.txt" +set /p DIST_DIR=<"%25GIT_PATH%25_LocalDev\dist_dir.txt" + +@echo Copying assemblies to Distribution $(Targetname) files... +if not exist "$(ProjectDir)Distribution\GameData\%25ModName%25\Plugins\" mkdir "$(ProjectDir)Distribution\GameData\%25ModName%25\Plugins\" +xcopy /E /Y "$(TargetDir)"BDArmory*.dll "$(ProjectDir)Distribution\GameData\%25ModName%25\Plugins\" + +if $(ConfigurationName) == Debug ( +@echo building debug files and symbols... +copy /Y "$(TargetDir)"BDArmory*.pdb "%25KSP_DIR%25\GameData\%25ModName%25\Plugins\" +) + +@echo deleting previous build ... +if exist "%25DIST_DIR%25\%25ModName%25.*.zip" del "%25DIST_DIR%25\%25ModName%25.*.zip" +@echo packaging new build... +call "%25ZA_DIR%25\7za.exe" a -tzip -r "%25DIST_DIR%25\%25ModName%25.@(VersionNumber)_%25DATE:~4,2%25%25DATE:~7,2%25%25DATE:~10,4%25%25time:~0,2%25%25time:~3,2%25.zip" "$(ProjectDir)Distribution\*.*" + +@echo Deploy $(ProjectDir) Distribution files to test env: %25KSP_DIR%25\GameData... +@echo copying:"$(ProjectDir)Distribution\GameData" to "%25KSP_DIR%25\GameData" +xcopy /E /Y "$(ProjectDir)Distribution\GameData" "%25KSP_DIR%25\GameData" + + +@echo Build/deploy complete! + + + + + + + + + + + + + $(PostBuildEventDependsOn); + PostBuildMacros; + + + + + + + \ No newline at end of file diff --git a/BDArmory/BDArmory.sln b/BDArmory/BDArmory.sln new file mode 100644 index 000000000..197553288 --- /dev/null +++ b/BDArmory/BDArmory.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.8 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDArmory", "BDArmory.csproj", "{D86F2003-1724-4F4C-BB5A-B0109CB16F35}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDArmory.Core", "..\BDArmory.Core\BDArmory.Core.csproj", "{A6F1753E-9570-4C40-AF72-A179890582E5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Debug|x86.ActiveCfg = Debug|Any CPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Debug|x86.Build.0 = Debug|Any CPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Release|Any CPU.Build.0 = Release|Any CPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Release|x86.ActiveCfg = Release|Any CPU + {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Release|x86.Build.0 = Release|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Debug|x86.ActiveCfg = Debug|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Debug|x86.Build.0 = Debug|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Release|Any CPU.Build.0 = Release|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Release|x86.ActiveCfg = Release|Any CPU + {A6F1753E-9570-4C40-AF72-A179890582E5}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A3A10DCC-85B5-49BC-8AAC-5547E4143101} + EndGlobalSection +EndGlobal diff --git a/BahaTurret/BahaTurret.cs b/BDArmory/BahaTurret.cs similarity index 98% rename from BahaTurret/BahaTurret.cs rename to BDArmory/BahaTurret.cs index 5fa871fd6..8bab38c05 100644 --- a/BahaTurret/BahaTurret.cs +++ b/BDArmory/BahaTurret.cs @@ -66,7 +66,9 @@ public class BahaTurret : PartModule [KSPField(isPersistant = false)] public float bulletMass = 5.40133e-5f; - [KSPField(isPersistant = false)] + [KSPField] + public float bulletDmgMult = 1; //Used for heat damage modifier for non-explosive bullets + [KSPField(isPersistant = false)] public float bulletVelocity = 860; [KSPField(isPersistant = false)] public string ammoName = "50CalAmmo"; @@ -266,9 +268,10 @@ public override void OnStart (PartModule.StartState state) { SetupTweakables(); - - - foreach(var pe in part.FindModelComponents()) + // Git Issue #39 StageIcon object is missing due to changes in KSP 1.1. added create to replace missing icon. + if (part.stackIcon.StageIcon == null) part.stackIcon.CreateIcon(); + + foreach (var pe in part.FindModelComponents()) { if(pe.useWorldSpace) { @@ -1135,8 +1138,8 @@ private bool FireLaser() } try { - Part p = Part.FromGO(hit.rigidbody.gameObject); - if(p.vessel!=this.vessel) + Part p = hit.collider.gameObject.GetComponentInParent(); + if (p.vessel!=this.vessel) { float distance = hit.distance; p.temperature += laserDamage/(float)(Math.PI*Math.Pow(tanAngle*distance,2))*TimeWarp.fixedDeltaTime; //distance modifier: 1/(PI*Pow(Dist*tan(angle), @@ -1177,8 +1180,8 @@ private void CheckTarget() { pointingAtPosition = hit.point; try{ - Part p = Part.FromGO(hit.rigidbody.gameObject); - hitPart = p; + Part p = hit.collider.gameObject.GetComponentInParent(); + hitPart = p; if(p.vessel == this.vessel) { inTurretRange = false; @@ -1228,7 +1231,7 @@ private void CheckTarget() Vessel hitVessel = null; try { - hitVessel = Part.FromGO(hit.rigidbody.gameObject).vessel; + hitVessel = hit.collider.gameObject.GetComponentInParent().vessel; } catch(NullReferenceException){} diff --git a/BahaTurret/BahaTurret.pidb b/BDArmory/BahaTurret.pidb similarity index 100% rename from BahaTurret/BahaTurret.pidb rename to BDArmory/BahaTurret.pidb diff --git a/BahaTurret/BahaTurret.userprefs b/BDArmory/BahaTurret.userprefs similarity index 100% rename from BahaTurret/BahaTurret.userprefs rename to BDArmory/BahaTurret.userprefs diff --git a/BDArmory/Bullets/BulletInfo.cs b/BDArmory/Bullets/BulletInfo.cs new file mode 100644 index 000000000..55df0a0cf --- /dev/null +++ b/BDArmory/Bullets/BulletInfo.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace BDArmory.Bullets +{ + public class BulletInfo + { + public string name { get; private set; } + public float caliber { get; private set; } + public float bulletMass { get; private set; } + public float bulletVelocity { get; private set; } + public bool explosive { get; private set; } + public float tntMass { get; private set; } + public float blastPower { get; private set; } + public float blastHeat { get; private set; } + public float blastRadius { get; private set; } + public float apBulletMod { get; private set; } + public string bulletDragTypeName { get; private set; } + + public static BulletInfos bullets; + + public BulletInfo(string name, float caliber, float bulletVelocity, float bulletMass, + bool explosive, float tntMass, float blastPower, float blastHeat, float blastRadius, + float apBulletDmg, string bulletDragTypeName) + + { + this.name = name; + this.caliber = caliber; + this.bulletVelocity = bulletVelocity; + this.bulletMass = bulletMass; + this.explosive = explosive; + this.tntMass = tntMass; + this.blastPower = blastPower; + this.blastHeat = blastHeat; + this.blastRadius = blastRadius; + this.apBulletMod = apBulletDmg; + this.bulletDragTypeName = bulletDragTypeName; + } + + public static void Load() + { + try + { + bullets = new BulletInfos(); + UrlDir.UrlConfig[] nodes = GameDatabase.Instance.GetConfigs("BULLET"); + for (int i = 0; i < nodes.Length; i++) + { + ConfigNode node = nodes[i].config; + bullets.Add( + new BulletInfo( + node.GetValue("name"), + float.Parse(node.GetValue("caliber")), + float.Parse(node.GetValue("bulletVelocity")), + float.Parse(node.GetValue("bulletMass")), + Convert.ToBoolean(node.GetValue("explosive")), + float.Parse(node.GetValue("tntMass")), + float.Parse(node.GetValue("blastPower")), + float.Parse(node.GetValue("blastHeat")), + float.Parse(node.GetValue("blastRadius")), + float.Parse(node.GetValue("apBulletMod")), + node.GetValue("bulletDragTypeName") + ) + ); + } + } + catch (Exception e) + { + Debug.Log("[BDArmory]: Error Loading Bullet Config | " + e.ToString()); + } + } + } + + public class BulletInfos : List + { + public BulletInfo this[string name] + { + get { return Find((value) => { return value.name == name; }); } + } + } +} diff --git a/BDArmory/Bullets/PooledBullet.cs b/BDArmory/Bullets/PooledBullet.cs new file mode 100644 index 000000000..33e1da145 --- /dev/null +++ b/BDArmory/Bullets/PooledBullet.cs @@ -0,0 +1,877 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Core.Module; +using BDArmory.FX; +using BDArmory.Parts; +using BDArmory.Shaders; +using UnityEngine; + +namespace BDArmory.Bullets +{ + public class PooledBullet : MonoBehaviour + { + #region Declarations + + public BulletInfo bullet; + public float leftPenetration; + + public enum PooledBulletTypes + { + Standard, + Explosive + } + + public enum BulletDragTypes + { + None, + AnalyticEstimate, + NumericalIntegration + } + + public PooledBulletTypes bulletType; + public BulletDragTypes dragType; + + public Vessel sourceVessel; + public Color lightColor = Misc.Misc.ParseColor255("255, 235, 145, 255"); + public Color projectileColor; + public string bulletTexturePath; + public bool fadeColor; + public Color startColor; + Color currentColor; + public bool bulletDrop = true; + public float tracerStartWidth = 1; + public float tracerEndWidth = 1; + public float tracerLength = 0; + public float tracerDeltaFactor = 1.35f; + public float tracerLuminance = 1; + public float initialSpeed; + + public Vector3 currPosition; + + //explosive parameters + public float radius = 30; + public float tntMass = 0; + public float blastPower = 8; + public float blastHeat = -1; + public float bulletDmgMult = 1; + public string explModelPath; + public string explSoundPath; + + Vector3 startPosition; + public bool airDetonation = false; + public bool proximityDetonation = false; + public float detonationRange = 5f; + public float defaultDetonationRange = 3500f; + public float maxAirDetonationRange = 3500f; + float randomWidthScale = 1; + LineRenderer bulletTrail; + public float timeToLiveUntil; + Light lightFlash; + bool wasInitiated; + public Vector3 currentVelocity; + public float bulletMass; + public float caliber = 1; + public float bulletVelocity; //muzzle velocity + public bool explosive = false; + public float apBulletMod = 0; + public float ballisticCoefficient; + public float flightTimeElapsed; + public static Shader bulletShader; + public static bool shaderInitialized; + private float impactVelocity; + private float dragVelocityFactor; + + public bool hasPenetrated = false; + public bool hasDetonated = false; + public bool hasRichocheted = false; + + public int penTicker = 0; + + public Rigidbody rb; + + #endregion Declarations + + private Vector3[] linePositions = new Vector3[2]; + + void OnEnable() + { + startPosition = transform.position; + initialSpeed = currentVelocity.magnitude; // this is the velocity used for drag estimations (only), use total velocity, not muzzle velocity + + if (!wasInitiated) + { + //projectileColor.a = projectileColor.a/2; + //startColor.a = startColor.a/2; + } + + projectileColor.a = Mathf.Clamp(projectileColor.a, 0.25f, 1f); + startColor.a = Mathf.Clamp(startColor.a, 0.25f, 1f); + currentColor = projectileColor; + if (fadeColor) + { + currentColor = startColor; + } + + if (lightFlash == null || !gameObject.GetComponent()) + { + lightFlash = gameObject.AddOrGetComponent(); + lightFlash.type = LightType.Point; + lightFlash.range = 8; + lightFlash.intensity = 1; + lightFlash.color = lightColor; + lightFlash.enabled = true; + } + + //tracer setup + if (bulletTrail == null || !gameObject.GetComponent()) + { + bulletTrail = gameObject.AddOrGetComponent(); + } + + if (!wasInitiated) + { + bulletTrail.positionCount = linePositions.Length; + } + linePositions[0] = transform.position; + linePositions[1] = transform.position; + bulletTrail.SetPositions(linePositions); + + if (!shaderInitialized) + { + shaderInitialized = true; + bulletShader = BDAShaderLoader.BulletShader; + } + + if (!wasInitiated) + { + bulletTrail.material = new Material(bulletShader); + randomWidthScale = UnityEngine.Random.Range(0.5f, 1f); + gameObject.layer = 15; + } + + bulletTrail.material.mainTexture = GameDatabase.Instance.GetTexture(bulletTexturePath, false); + bulletTrail.material.SetColor("_TintColor", currentColor); + bulletTrail.material.SetFloat("_Lum", tracerLuminance); + + tracerStartWidth *= 2f; + tracerEndWidth *= 2f; + + leftPenetration = 1; + wasInitiated = true; + StartCoroutine(FrameDelayedRoutine()); + } + + void OnDestroy() + { + StopCoroutine(FrameDelayedRoutine()); + } + + IEnumerator FrameDelayedRoutine() + { + yield return new WaitForFixedUpdate(); + lightFlash.enabled = false; + } + + void OnWillRenderObject() + { + if (!gameObject.activeInHierarchy) + { + return; + } + Camera currentCam = Camera.current; + if (TargetingCamera.IsTGPCamera(currentCam)) + { + UpdateWidth(currentCam, 4); + } + else + { + UpdateWidth(currentCam, 1); + } + } + + void FixedUpdate() + { + if (!gameObject.activeInHierarchy) + { + return; + } + + //floating origin and velocity offloading corrections + if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) + { + transform.position -= FloatingOrigin.OffsetNonKrakensbane; + startPosition -= FloatingOrigin.OffsetNonKrakensbane; + } + + float distanceFromStart = Vector3.Distance(transform.position, startPosition); + + //calculate flight time for drag purposes + flightTimeElapsed += Time.fixedDeltaTime; + + //Drag types currently only affect Impactvelocity + //Numerical Integration is currently Broken + switch (dragType) + { + case BulletDragTypes.None: + break; + + case BulletDragTypes.AnalyticEstimate: + CalculateDragAnalyticEstimate(); + break; + + case BulletDragTypes.NumericalIntegration: + CalculateDragNumericalIntegration(); + break; + } + + if (tracerLength == 0) + { + // visual tracer velocity is relative to the observer + linePositions[0] = transform.position + + ((currentVelocity - FlightGlobals.ActiveVessel.Velocity()) * tracerDeltaFactor * 0.45f * Time.fixedDeltaTime); + } + else + { + linePositions[0] = transform.position + ((currentVelocity - FlightGlobals.ActiveVessel.Velocity()).normalized * tracerLength); + } + + if (fadeColor) + { + FadeColor(); + bulletTrail.material.SetColor("_TintColor", currentColor * tracerLuminance); + } + linePositions[1] = transform.position; + + bulletTrail.SetPositions(linePositions); + currPosition = transform.position; + + if (Time.time > timeToLiveUntil) //kill bullet when TTL ends + { + KillBullet(); + return; + } + + // bullet collision block + { + //reset our hit variables to default state + hasPenetrated = true; + hasDetonated = false; + hasRichocheted = false; + penTicker = 0; + + float dist = currentVelocity.magnitude * Time.fixedDeltaTime; + Ray ray = new Ray(currPosition, currentVelocity); + var hits = Physics.RaycastAll(ray, dist, 9076737); + if (hits.Length > 0) + { + var orderedHits = hits.OrderBy(x => x.distance); + + using (var hitsEnu = orderedHits.GetEnumerator()) + { + while (hitsEnu.MoveNext()) + { + if (!hasPenetrated || hasRichocheted || hasDetonated) break; + + RaycastHit hit = hitsEnu.Current; + Part hitPart = null; + KerbalEVA hitEVA = null; + + try + { + hitPart = hit.collider.gameObject.GetComponentInParent(); + hitEVA = hit.collider.gameObject.GetComponentUpwards(); + } + catch (NullReferenceException) + { + Debug.Log("[BDArmory]:NullReferenceException for Ballistic Hit"); + return; + } + + if (hitEVA != null) + { + hitPart = hitEVA.part; + // relative velocity, separate from the below statement, because the hitpart might be assigned only above + if (hitPart?.rb != null) + impactVelocity = (currentVelocity * dragVelocityFactor + - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f())).magnitude; + else + impactVelocity = currentVelocity.magnitude * dragVelocityFactor; + ApplyDamage(hitPart, hit, 1, 1); + break; + } + + if (hitPart?.vessel == sourceVessel) continue; //avoid autohit; + + Vector3 impactVector = currentVelocity; + if (hitPart?.rb != null) + // using relative velocity vector instead of just bullet velocity + // since KSP vessels might move faster than bullets + impactVector = (currentVelocity * dragVelocityFactor + - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f())); + + float hitAngle = Vector3.Angle(impactVector, -hit.normal); + + if (CheckGroundHit(hitPart, hit)) + { + CheckBuildingHit(hit); + if (!RicochetScenery(hitAngle)) + { + ExplosiveDetonation(hitPart, hit, ray); + KillBullet(); + } + else + { + DoRicochet(hitPart, hit, hitAngle); + } + return; + } + + //Standard Pipeline Hitpoints, Armor and Explosives + + impactVelocity = impactVector.magnitude; + float anglemultiplier = (float)Math.Cos(Math.PI * hitAngle / 180.0); + + float penetrationFactor = CalculateArmorPenetration(hitPart, anglemultiplier, hit); + + if (penetrationFactor >= 2) + { + //its not going to bounce if it goes right through + hasRichocheted = false; + } + else + { + if (RicochetOnPart(hitPart, hit, hitAngle, impactVelocity)) + hasRichocheted = true; + } + + if (penetrationFactor > 1 && !hasRichocheted) //fully penetrated continue ballistic damage + { + hasPenetrated = true; + ApplyDamage(hitPart, hit, 1, penetrationFactor); + penTicker += 1; + CheckPartForExplosion(hitPart); + + //Explosive bullets that penetrate should explode shortly after + //if penetration is very great, they will have moved on + //checking velocity as they would not be able to come out the other side + //if (explosive && penetrationFactor < 3 || currentVelocity.magnitude <= 800f) + if (explosive) + { + //move bullet + transform.position += (currentVelocity * Time.fixedDeltaTime) / 3; + + ExplosiveDetonation(hitPart, hit, ray); + hasDetonated = true; + KillBullet(); + } + } + else if (!hasRichocheted) // explosive bullets that get stopped by armor will explode + { + //New method + + if (hitPart.rb != null) + { + float forceAverageMagnitude = impactVelocity * impactVelocity * + (1f / hit.distance) * (bulletMass - tntMass); + + float accelerationMagnitude = + forceAverageMagnitude / (hitPart.vessel.GetTotalMass() * 1000); + + hitPart?.rb.AddForceAtPosition(impactVector.normalized * accelerationMagnitude, hit.point, ForceMode.Acceleration); + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Force Applied " + Math.Round(accelerationMagnitude, 2) + "| Vessel mass in kgs=" + hitPart.vessel.GetTotalMass() * 1000 + "| bullet effective mass =" + (bulletMass - tntMass)); + } + + hasPenetrated = false; + ApplyDamage(hitPart, hit, 1, penetrationFactor); + ExplosiveDetonation(hitPart, hit, ray); + hasDetonated = true; + KillBullet(); + } + + ///////////////////////////////////////////////////////////////////////////////// + // penetrated after a few ticks + ///////////////////////////////////////////////////////////////////////////////// + + //penetrating explosive + //richochets + + if ((penTicker >= 2 && explosive) || (hasRichocheted && explosive)) + { + //detonate + ExplosiveDetonation(hitPart, hit, ray, airDetonation); + return; + } + + //bullet should not go any further if moving too slowly after hit + //smaller caliber rounds would be too deformed to do any further damage + if (currentVelocity.magnitude <= 100 && hasPenetrated) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Bullet Velocity too low, stopping"); + } + KillBullet(); + return; + } + //we need to stop the loop if the bullet has stopped,richochet or detonated + if (!hasPenetrated || hasRichocheted || hasDetonated) break; + }//end While + }//end enumerator + }//end if hits + }// end if collision + + ////////////////////////////////////////////////// + //Flak Explosion (air detonation/proximity fuse) + ////////////////////////////////////////////////// + + if (ProximityAirDetonation(distanceFromStart)) + { + //detonate + ExplosionFx.CreateExplosion(currPosition, tntMass, explModelPath, explSoundPath, false, caliber, null, currentVelocity); + KillBullet(); + + return; + } + + if (bulletDrop) + { + // Gravity??? + var gravity_ = FlightGlobals.getGeeForceAtPosition(transform.position); + //var gravity_ = Physics.gravity; + currentVelocity += gravity_ * TimeWarp.deltaTime; + } + + //move bullet + transform.position += currentVelocity * Time.fixedDeltaTime; + } + + private bool ProximityAirDetonation(float distanceFromStart) + { + bool detonate = false; + + if (distanceFromStart <= 500f) return false; + + if (explosive && airDetonation) + { + if (distanceFromStart > maxAirDetonationRange || distanceFromStart > defaultDetonationRange) + { + return detonate = true; + } + + if (proximityDetonation) + { + using (var hitsEnu = Physics.OverlapSphere(transform.position, detonationRange, 557057).AsEnumerable().GetEnumerator()) + { + while (hitsEnu.MoveNext()) + { + if (hitsEnu.Current == null) continue; + + try + { + Part partHit = hitsEnu.Current.GetComponentInParent(); + if (partHit?.vessel == sourceVessel) continue; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Bullet proximity sphere hit | Distance overlap = " + detonationRange + "| Part name = " + partHit.name); + + return detonate = true; + } + catch + { + // ignored + } + } + } + } + } + return detonate; + } + + private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float penetrationfactor) + { + //hitting a vessel Part + //No struts, they cause weird bugs :) -BahamutoD + if (hitPart == null) return; + if (hitPart.partInfo.name.Contains("Strut")) return; + + if (BDArmorySettings.BULLET_HITS) + { + BulletHitFX.CreateBulletHit(hitPart, hit.point, hit, hit.normal, hasRichocheted, caliber, + penetrationfactor); + } + + if (explosive) + { + hitPart.AddBallisticDamage(bulletMass - tntMass, caliber, multiplier, penetrationfactor, + bulletDmgMult, impactVelocity); + } + else + { + hitPart.AddBallisticDamage(bulletMass, caliber, multiplier, penetrationfactor, + bulletDmgMult, impactVelocity); + } + } + + private void CalculateDragNumericalIntegration() + { + Vector3 dragAcc = currentVelocity * currentVelocity.magnitude * + (float) + FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), + FlightGlobals.getExternalTemperature(transform.position)); + dragAcc *= 0.5f; + dragAcc /= ballisticCoefficient; + + currentVelocity -= dragAcc * TimeWarp.deltaTime; + //numerical integration; using Euler is silly, but let's go with it anyway + } + + private void CalculateDragAnalyticEstimate() + { + float analyticDragVelAdjustment = (float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPosition), FlightGlobals.getExternalTemperature(currPosition)); + analyticDragVelAdjustment *= flightTimeElapsed * initialSpeed; + analyticDragVelAdjustment += 2 * ballisticCoefficient; + + analyticDragVelAdjustment = 2 * ballisticCoefficient * initialSpeed / analyticDragVelAdjustment; + //velocity as a function of time under the assumption of a projectile only acted upon by drag with a constant drag area + + dragVelocityFactor = analyticDragVelAdjustment / initialSpeed; + } + + private float CalculateArmorPenetration(Part hitPart, float anglemultiplier, RaycastHit hit) + { + /////////////////////////////////////////////////////////////////////// + // Armor Penetration + /////////////////////////////////////////////////////////////////////// + + float penetration = CalculatePenetration(); + + //TODO: Extract bdarmory settings from this values + float thickness = CalculateThickness(hitPart, anglemultiplier); + if (thickness < 1) thickness = 1; //prevent divide by zero or other odd behavior + + var penetrationFactor = penetration / thickness; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Armor penetration = " + penetration + " | Thickness = " + thickness); + } + + bool fullyPenetrated = penetration > thickness; //check whether bullet penetrates the plate + + double massToReduce = Math.PI * Math.Pow((caliber * 0.001) / 2, 2) * (penetration); + + if (fullyPenetrated) + { + //lower velocity on penetrating armor plate + //does not affect low impact parts so that rounds can go through entire tank easily + //If round penetrates easily it should not loose much velocity + + //if (penetrationFactor < 2) + currentVelocity = currentVelocity * (float)Math.Sqrt(thickness / penetration); + //signifincanly reduce velocity on subsequent penetrations + if (penTicker > 0) currentVelocity *= 0.55f; + + //updating impact velocity + //impactVelocity = currentVelocity.magnitude; + + flightTimeElapsed -= Time.fixedDeltaTime; + } + else + { + massToReduce *= 0.125f; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Bullet Stopped by Armor"); + } + } + hitPart.ReduceArmor(massToReduce); + return penetrationFactor; + } + + private float CalculatePenetration() + { + float penetration = 0; + if (caliber > 10) //use the "krupp" penetration formula for anything larger than HMGs + { + penetration = (float)(16f * impactVelocity * Math.Sqrt(bulletMass / 1000) / Math.Sqrt(caliber)); + } + + return penetration; + } + + private static float CalculateThickness(Part hitPart, float anglemultiplier) + { + float thickness = (float)hitPart.GetArmorThickness(); + return Mathf.Max(thickness / anglemultiplier, 1); + } + + private bool ExplosiveDetonation(Part hitPart, RaycastHit hit, Ray ray, bool airDetonation = false) + { + /////////////////////////////////////////////////////////////////////// + // High Explosive Detonation + /////////////////////////////////////////////////////////////////////// + + if (hitPart == null || hitPart.vessel != sourceVessel) + { + //if bullet hits and is HE, detonate and kill bullet + if (explosive) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Detonation Triggered | penetration: " + hasPenetrated + " penTick: " + penTicker + " airDet: " + airDetonation); + } + + if (airDetonation) + { + ExplosionFx.CreateExplosion(hit.point, GetExplosivePower(), explModelPath, explSoundPath, false, caliber); + } + else + { + ExplosionFx.CreateExplosion(hit.point - (ray.direction * 0.1f), + GetExplosivePower(), + explModelPath, explSoundPath, false, caliber, null, direction: currentVelocity); + } + + KillBullet(); + hasDetonated = true; + return true; + } + } + return false; + } + + private bool CheckGroundHit(Part hitPart, RaycastHit hit) + { + if (hitPart == null) + { + if (BDArmorySettings.BULLET_HITS) + { + BulletHitFX.CreateBulletHit(hitPart, hit.point, hit, hit.normal, true, caliber, 0); + } + + return true; + } + return false; + } + + private bool CheckBuildingHit(RaycastHit hit) + { + DestructibleBuilding building = null; + try + { + building = hit.collider.gameObject.GetComponentUpwards(); + building.damageDecay = 600f; + } + catch (Exception) { } + + if (building != null && building.IsIntact) + { + float damageToBuilding = ((0.5f * (bulletMass * Mathf.Pow(currentVelocity.magnitude, 2))) + * (BDArmorySettings.DMG_MULTIPLIER / 100) * bulletDmgMult + * 1e-4f); + damageToBuilding /= 8f; + building.AddDamage(damageToBuilding); + if (building.Damage > building.impactMomentumThreshold * 150) + { + building.Demolish(); + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Ballistic hit destructible building! Hitpoints Applied: " + Mathf.Round(damageToBuilding) + + ", Building Damage : " + Mathf.Round(building.Damage) + + " Building Threshold : " + building.impactMomentumThreshold); + + return true; + } + return false; + } + + public void UpdateWidth(Camera c, float resizeFactor) + { + if (c == null) + { + return; + } + if (bulletTrail == null) + { + return; + } + if (!gameObject.activeInHierarchy) + { + return; + } + + float fov = c.fieldOfView; + float factor = (fov / 60) * resizeFactor * + Mathf.Clamp(Vector3.Distance(transform.position, c.transform.position), 0, 3000) / 50; + bulletTrail.startWidth = tracerStartWidth * factor * randomWidthScale; + bulletTrail.endWidth = tracerEndWidth * factor * randomWidthScale; + } + + void KillBullet() + { + gameObject.SetActive(false); + } + + void FadeColor() + { + Vector4 endColorV = new Vector4(projectileColor.r, projectileColor.g, projectileColor.b, projectileColor.a); + float delta = TimeWarp.deltaTime; + Vector4 finalColorV = Vector4.MoveTowards(currentColor, endColorV, delta); + currentColor = new Color(finalColorV.x, finalColorV.y, finalColorV.z, Mathf.Clamp(finalColorV.w, 0.25f, 1f)); + } + + bool RicochetOnPart(Part p, RaycastHit hit, float angleFromNormal, float impactVel) + { + float hitTolerance = p.crashTolerance; + //15 degrees should virtually guarantee a ricochet, but 75 degrees should nearly always be fine + float chance = (((angleFromNormal - 5) / 75) * (hitTolerance / 150)) * 100 / Mathf.Clamp01(impactVel / 600); + float random = UnityEngine.Random.Range(0f, 100f); + if (BDArmorySettings.DRAW_DEBUG_LABELS) Debug.Log("[BDArmory]: Ricochet chance: " + chance); + if (random < chance) + { + DoRicochet(p, hit, angleFromNormal); + return true; + } + else + { + return false; + } + } + + bool RicochetScenery(float hitAngle) + { + float reflectRandom = UnityEngine.Random.Range(-75f, 90f); + if (reflectRandom > 90 - hitAngle && caliber <= 30f) + { + return true; + } + + return false; + } + + public void DoRicochet(Part p, RaycastHit hit, float hitAngle) + { + //ricochet + if (BDArmorySettings.BULLET_HITS) + { + BulletHitFX.CreateBulletHit(p, hit.point, hit, hit.normal, true, caliber, 0); + } + + tracerStartWidth /= 2; + tracerEndWidth /= 2; + + transform.position = hit.point; + currentVelocity = Vector3.Reflect(currentVelocity, hit.normal); + currentVelocity = (hitAngle / 150) * currentVelocity * 0.65f; + + Vector3 randomDirection = UnityEngine.Random.rotation * Vector3.one; + + currentVelocity = Vector3.RotateTowards(currentVelocity, randomDirection, + UnityEngine.Random.Range(0f, 5f) * Mathf.Deg2Rad, 0); + } + + public void CheckPartForExplosion(Part hitPart) + { + if (!hitPart.FindModuleImplementing()) return; + + switch (hitPart.GetExplodeMode()) + { + case "Always": + CreateExplosion(hitPart); + break; + + case "Dynamic": + float probability = CalculateExplosionProbability(hitPart); + if (probability >= 3) + CreateExplosion(hitPart); + break; + + case "Never": + break; + } + } + + private float CalculateExplosionProbability(Part part) + { + /////////////////////////////////////////////////////////////// + float probability = 0; + float fuelPct = 0; + for (int i = 0; i < part.Resources.Count; i++) + { + PartResource current = part.Resources[i]; + switch (current.resourceName) + { + case "LiquidFuel": + fuelPct = (float)(current.amount / current.maxAmount); + break; + //case "Oxidizer": + // probability += (float) (current.amount/current.maxAmount); + // break; + } + } + + if (fuelPct > 0 && fuelPct <= 0.60f) + { + probability = Core.Utils.BDAMath.RangedProbability(new[] { 50f, 25f, 20f, 5f }); + } + else + { + probability = Core.Utils.BDAMath.RangedProbability(new[] { 50f, 25f, 20f, 2f }); + } + + if (fuelPct == 1f || fuelPct == 0f) + probability = 0f; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Explosive Probablitliy " + probability); + } + + return probability; + } + + public void CreateExplosion(Part part) + { + float explodeScale = 0; + IEnumerator resources = part.Resources.GetEnumerator(); + while (resources.MoveNext()) + { + if (resources.Current == null) continue; + switch (resources.Current.resourceName) + { + case "LiquidFuel": + explodeScale += (float)resources.Current.amount; + break; + + case "Oxidizer": + explodeScale += (float)resources.Current.amount; + break; + } + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Penetration of bullet detonated fuel!"); + } + + resources.Dispose(); + + explodeScale /= 100; + part.explosionPotential = explodeScale; + + PartExploderSystem.AddPartToExplode(part); + } + + private float GetExplosivePower() + { + return tntMass > 0 ? tntMass : blastPower; + } + } +} diff --git a/BDArmory/CodeMap/SmartFindTarget.dgml b/BDArmory/CodeMap/SmartFindTarget.dgml new file mode 100644 index 000000000..48fb17c63 --- /dev/null +++ b/BDArmory/CodeMap/SmartFindTarget.dgml @@ -0,0 +1,634 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BDArmory/Control/AIUtils.cs b/BDArmory/Control/AIUtils.cs new file mode 100644 index 000000000..26ceef0e2 --- /dev/null +++ b/BDArmory/Control/AIUtils.cs @@ -0,0 +1,569 @@ +using System; +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Misc; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Control +{ + public static class AIUtils + { + /// + /// Predict a future position of a vessel given its current position, velocity and acceleration + /// + /// vessel to be extrapolated + /// after this time + /// Vector3 extrapolated position + public static Vector3 PredictPosition(this Vessel v, float time) + { + Vector3 pos = v.CoM; + pos += v.Velocity() * time; + pos += 0.5f * v.acceleration * time * time; + return pos; + } + + /// + /// Get the altitude of terrain below/above a point. + /// + /// World position, not geo position (use VectorUtils.GetWorldSurfacePostion to convert lat,long,alt to world position) + /// usually vessel.MainBody + /// terrain height + public static float GetTerrainAltitude(Vector3 position, CelestialBody body, bool underwater = true) + { + return (float)body.TerrainAltitude(body.GetLatitude(position), body.GetLongitude(position), underwater); + } + + /// + /// Get the local position of your place in a formation + /// + /// index of formation position + /// vector of location relative to your commandLeader + public static Vector3 GetLocalFormationPosition(this IBDAIControl ai, int index) + { + if (ai.commandLeader == null) return Vector3.zero; + + float indexF = (float)index; + indexF++; + + float rightSign = indexF % 2 == 0 ? -1 : 1; + float positionFactor = Mathf.Ceil(indexF / 2); + float spread = ai.commandLeader.spread; + float lag = ai.commandLeader.lag; + + float right = rightSign * positionFactor * spread; + float back = positionFactor * lag * -1; + + return new Vector3(right, back, 0); + } + + [Flags] + public enum VehicleMovementType + { + Stationary = 0, + Land = 1, + Water = 2, + Amphibious = Land | Water, + } + + /// + /// Minimum depth for water ships to consider the terrain safe. + /// + public const float MinDepth = -10f; + + /// + /// A grid approximation for a spherical body for AI pathing purposes. + /// + public class TraversabilityMatrix + { + // edge of each grid cell + const float GridSizeDefault = 400f; + const float GiveUpHeuristicMultiplier = 3; + const float RetraceReluctanceMultiplier = 1.01f; + float GridSize; + float GridDiagonal; + + // how much the gird can get distorted before it is rebuilt instead of expanded + const float MaxDistortion = 0.02f; + + Dictionary grid = new Dictionary(); + Dictionary cornerAlts; + + float rebuildDistance; + CelestialBody body; + float maxSlopeAngle; + Vector3 origin; + VehicleMovementType movementType; + + /// + /// Create a new traversability matrix. + /// + /// Origin point, in Lat,Long,Alt form + /// Destination point, in Lat,Long,Alt form + /// Body on which the grid is created + /// Movement type of the vehicle (surface/land) + /// The highest slope angle (in degrees) the vessel can traverse in a straight line + /// List of geo coordinate vectors of waypoints to traverse in straight lines to reach the destination + public List Pathfind(Vector3 start, Vector3 end, CelestialBody body, VehicleMovementType vehicleType, float maxSlopeAngle, float minObstacleMass) + { + checkGrid(start, body, vehicleType, maxSlopeAngle, minObstacleMass, + Mathf.Clamp(VectorUtils.GeoDistance(start, end, body) / 20, GridSizeDefault, GridSizeDefault * 5)); + + Coords startCoords = getGridCoord(start); + Coords endCoords = getGridCoord(end); + float initialDistance = gridDistance(startCoords, endCoords); + + SortedDictionary sortedCandidates = new SortedDictionary(new CellValueComparer()) + { [new CellValue(getCellAt(startCoords), initialDistance)] = 0 }; //(openSet and fScore), gScore + Dictionary candidates = new Dictionary + { [getCellAt(startCoords)] = initialDistance }; // secondary dictionary to sortedCandidates for faster lookup + + Dictionary nodes = new Dictionary //gScore + { [getCellAt(startCoords)] = 0 }; + + Dictionary backtrace = new Dictionary(); //cameFrom + HashSet visited = new HashSet(); + + Cell current = null; + float currentFScore = 0; + KeyValuePair best = new KeyValuePair(getCellAt(startCoords), initialDistance * GiveUpHeuristicMultiplier); + + List> adjacent = new List>(8) + { + new KeyValuePair(new Coords(0, 1), GridSize), + new KeyValuePair(new Coords(1, 0), GridSize), + new KeyValuePair(new Coords(0, -1), GridSize), + new KeyValuePair(new Coords(-1, 0), GridSize), + new KeyValuePair(new Coords(1, 1), GridDiagonal), + new KeyValuePair(new Coords(1, -1), GridDiagonal), + new KeyValuePair(new Coords(-1, -1), GridDiagonal), + new KeyValuePair(new Coords(-1, 1), GridDiagonal), + }; + + while (candidates.Count > 0) + { + // take the best candidate - since now we use SortedDict, it's the first one + using (var e = sortedCandidates.GetEnumerator()) + { + e.MoveNext(); + current = e.Current.Key.Cell; + currentFScore = e.Current.Key.Value; + candidates.Remove(e.Current.Key.Cell); + sortedCandidates.Remove(e.Current.Key); + } + // stop if we found our destination + if (current.Coords == endCoords) + break; + if (currentFScore > best.Value) + { + current = best.Key; + break; + } + + visited.Add(current); + float currentNodeScore = nodes[current]; + + using (var adj = adjacent.GetEnumerator()) + while (adj.MoveNext()) + { + Cell neighbour = getCellAt(current.Coords + adj.Current.Key); + if (!neighbour.Traversable || visited.Contains(neighbour)) continue; + if (candidates.TryGetValue(neighbour, out float value)) + { + if (currentNodeScore + adj.Current.Value >= value) + continue; + else + sortedCandidates.Remove(new CellValue(neighbour, value)); //we'll reinsert with the adjusted value, so it's sorted properly + } + nodes[neighbour] = currentNodeScore + adj.Current.Value; + backtrace[neighbour] = current; + float remainingDistanceEstimate = gridDistance(neighbour.Coords, endCoords); + float fScoreEstimate = currentNodeScore + adj.Current.Value + remainingDistanceEstimate * RetraceReluctanceMultiplier; + sortedCandidates[new CellValue(neighbour, fScoreEstimate)] = currentNodeScore + adj.Current.Value; + candidates[neighbour] = currentNodeScore + adj.Current.Value; + if ((fScoreEstimate + remainingDistanceEstimate * (GiveUpHeuristicMultiplier - 1)) < best.Value) + best = new KeyValuePair(neighbour, fScoreEstimate + remainingDistanceEstimate * (GiveUpHeuristicMultiplier - 1)); + } + } + + var path = new List(); + while (current.Coords != startCoords) + { + path.Add(current); + current = backtrace[current]; + } + path.Reverse(); + + if (path.Count > 2) + { + var newPath = new List() { path[0] }; + for (int i = 1; i < path.Count - 1; ++i) + { + if (path[i].Coords - path[i - 1].Coords != path[i + 1].Coords - path[1].Coords) + newPath.Add(path[i]); + } + newPath.Add(path[path.Count - 1]); + path = newPath; + } + + var pathReduced = new List(); + Coords waypoint = startCoords; + for (int i = 1; i < path.Count; ++i) + { + if (!straightPath(waypoint.X, waypoint.Y, path[i].X, path[i].Y)) + { + pathReduced.Add(path[i - 1].GeoPos); + waypoint = path[i - 1].Coords; + } + } + + // if not path found + if (path.Count == 0) + { + if (startCoords == endCoords) + pathReduced.Add(end); + else + pathReduced.Add(start); + } + else if (path[path.Count - 1].Coords == endCoords) + pathReduced.Add(end); + else + pathReduced.Add(path[path.Count - 1].GeoPos); + + return pathReduced; + } + + /// + /// Check if line is traversable. Due to implementation specifics, it is advised not to use this if the start point is not the position of the vessel. + /// + /// start point in Lat,Long,Alt form + /// end point, in Lat,Long,Alt form + public bool TraversableStraightLine(Vector3 startGeo, Vector3 endGeo, CelestialBody body, VehicleMovementType vehicleType, float maxSlopeAngle, float minObstacleMass) + { + checkGrid(startGeo, body, vehicleType, maxSlopeAngle, minObstacleMass); + return TraversableStraightLine(startGeo, endGeo); + } + + public bool TraversableStraightLine(Vector3 startGeo, Vector3 endGeo) + { + float[] location = getGridLocation(startGeo); + float[] endPos = getGridLocation(endGeo); + + return straightPath(location[0], location[1], endPos[0], endPos[1]); + } + + private void checkGrid(Vector3 origin, CelestialBody body, VehicleMovementType vehicleType, float maxSlopeAngle, float minMass, float gridSize = GridSizeDefault) + { + if (grid == null || VectorUtils.GeoDistance(this.origin, origin, body) > rebuildDistance || Mathf.Abs(gridSize - GridSize) > 100 || + this.body != body || movementType != vehicleType || this.maxSlopeAngle != maxSlopeAngle * Mathf.Deg2Rad) + { + GridSize = gridSize; + GridDiagonal = gridSize * Mathf.Sqrt(2); + this.body = body; + this.maxSlopeAngle = maxSlopeAngle * Mathf.Deg2Rad; + rebuildDistance = Mathf.Clamp(Mathf.Asin(MaxDistortion) * (float)body.Radius, GridSize * 4, GridSize * 256); + movementType = vehicleType; + this.origin = origin; + grid = new Dictionary(); + cornerAlts = new Dictionary(); + } + includeDebris(minMass); + } + + private Cell getCellAt(int x, int y) => getCellAt(new Coords(x, y)); + + private Cell getCellAt(Coords coords) + { + if (!grid.TryGetValue(coords, out Cell cell)) + { + cell = new Cell(coords, gridToGeo(coords), CheckTraversability(coords), body); + grid[coords] = cell; + } + return cell; + } + + /// + /// Check all debris on the ground, and mark those squares impassable. + /// + private void includeDebris(float minMass) + { + using (var vs = BDATargetManager.LoadedVessels.GetEnumerator()) + while (vs.MoveNext()) + { + if ((vs.Current == null || vs.Current.vesselType != VesselType.Debris || vs.Current.IsControllable || !vs.Current.LandedOrSplashed + || vs.Current.mainBody.GetAltitude(vs.Current.CoM) < MinDepth || vs.Current.GetTotalMass() < minMass)) continue; + + var debrisPos = getGridLocation(VectorUtils.WorldPositionToGeoCoords(vs.Current.CoM, body)); + var coordArray = new List + { + new Coords(Mathf.CeilToInt(debrisPos[0]), Mathf.CeilToInt(debrisPos[1])), + new Coords(Mathf.CeilToInt(debrisPos[0]), Mathf.FloorToInt(debrisPos[1])), + new Coords(Mathf.FloorToInt(debrisPos[0]), Mathf.CeilToInt(debrisPos[1])), + new Coords(Mathf.FloorToInt(debrisPos[0]), Mathf.FloorToInt(debrisPos[1])), + }; + using (var coords = coordArray.GetEnumerator()) + { + while (coords.MoveNext()) + { + if (grid.TryGetValue(coords.Current, out Cell cell)) + cell.Traversable = false; + else + grid[coords.Current] = new Cell(coords.Current, gridToGeo(coords.Current), false, body); + } + } + } + } + + private bool straightPath(float originX, float originY, float destX, float destY) + { + float dX = (destX - originX); + float dY = (destY - originY); + int dirX = Math.Sign(dX); + int dirY = Math.Sign(dY); + int sX = Mathf.RoundToInt(originX); + int sY = Mathf.RoundToInt(originY); + + int xP = 0; + int yP = 0; + float xT = Mathf.Abs(dX); + float yT = Mathf.Abs(dY); + + while (xP < xT || yP < yT) + { + float ratio = Mathf.Abs(Mathf.Max(xT - xP, 0) / Mathf.Max(yT - yP, 0)); + + if (ratio > 0.49) + ++xP; + if (ratio < 2.04) + ++yP; + + if (!getCellAt(sX + xP * dirX, sY + yP * dirY).Traversable) + return false; + } + + return true; + } + + // calculate location on grid + private float[] getGridLocation(Vector3 geoPoint) + { + var distance = VectorUtils.GeoDistance(origin, geoPoint, body) / GridSize; + var bearing = VectorUtils.GeoForwardAzimuth(origin, geoPoint) * Mathf.Deg2Rad; + var x = distance * Mathf.Cos(bearing); + var y = distance * Mathf.Sin(bearing); + return new float[2] { x, y }; + } + + // round grid coordinates to get cell + private Coords getGridCoord(float[] gridLocation) + => new Coords(Mathf.RoundToInt(gridLocation[0]), Mathf.RoundToInt(gridLocation[1])); + + private Coords getGridCoord(Vector3 geoPosition) + => getGridCoord(getGridLocation(geoPosition)); + + private float gridDistance(Coords point, Coords other) + { + float dX = Mathf.Abs(point.X - other.X); + float dY = Mathf.Abs(point.Y - other.Y); + return GridDiagonal * Mathf.Min(dX, dY) + GridSize * Mathf.Abs(dX - dY); + } + + // positive y towards north, positive x towards east + Vector3 gridToGeo(float x, float y) + { + if (x == 0 && y == 0) return origin; + return VectorUtils.GeoCoordinateOffset(origin, body, Mathf.Atan2(y, x) * Mathf.Rad2Deg, Mathf.Sqrt(x * x + y * y) * GridSize); + } + + Vector3 gridToGeo(Coords coords) => gridToGeo(coords.X, coords.Y); + + private class Cell + { + public Cell(Coords coords, Vector3 geoPos, bool traversable, CelestialBody body) + { + Coords = coords; + GeoPos = geoPos; + GeoPos.z = (float)body.TerrainAltitude(GeoPos.x, GeoPos.y); + Traversable = traversable; + this.body = body; + } + + private CelestialBody body; + public readonly Coords Coords; + public readonly Vector3 GeoPos; + public Vector3 WorldPos => VectorUtils.GetWorldSurfacePostion(GeoPos, body); + public bool Traversable; + + public int X => Coords.X; + public int Y => Coords.Y; + + public override string ToString() => $"[{X}, {Y}, {Traversable}]"; + + public override int GetHashCode() => Coords.GetHashCode(); + + public bool Equals(Cell other) => X == other?.X && Y == other.Y && Traversable == other.Traversable; + + public override bool Equals(object obj) => Equals(obj as Cell); + + public static bool operator ==(Cell left, Cell right) => object.Equals(left, right); + + public static bool operator !=(Cell left, Cell right) => !object.Equals(left, right); + } + + private struct CellValue + { + public CellValue(Cell cell, float value) + { + Cell = cell; + Value = value; + } + + public readonly Cell Cell; + public readonly float Value; + + public override int GetHashCode() => Cell.Coords.GetHashCode(); + } + + private class CellValueComparer : IComparer + { + /// + /// This a very specific implementation for pathfinding to make use of the sorted dictionary. + /// It is non-commutative and not order-invariant. + /// But that is exactly how we want it right now. + /// + /// Lies and misinformation of the best kind. + public int Compare(CellValue x, CellValue y) + { + if (x.Cell.Equals(y.Cell)) + return 0; + if (x.Value > y.Value) + return 1; + return -1; + } + } + + // because int[] does not produce proper hashes + private struct Coords + { + public readonly int X; + public readonly int Y; + + public Coords(int x, int y) + { + X = x; + Y = y; + } + + public bool Equals(Coords other) + { + if (other == null) return false; + return (X == other.X && Y == other.Y); + } + + public override bool Equals(object obj) + { + if (!(obj is Coords)) return false; + return Equals((Coords)obj); + } + + public static bool operator ==(Coords left, Coords right) => object.Equals(left, right); + + public static bool operator !=(Coords left, Coords right) => !object.Equals(left, right); + + public static Coords operator +(Coords left, Coords right) => new Coords(left.X + right.X, left.Y + right.Y); + + public static Coords operator -(Coords left, Coords right) => new Coords(left.X - right.X, left.Y - right.Y); + + public override int GetHashCode() => X.GetHashCode() * 1009 + Y.GetHashCode(); + + public override string ToString() => $"[{X}, {Y}]"; + } + + private float getCornerAlt(int x, int y) => getCornerAlt(new Coords(x, y)); + + private float getCornerAlt(Coords coords) + { + if (!cornerAlts.TryGetValue(coords, out float alt)) + { + var geo = gridToGeo(coords.X - 0.5f, coords.Y - 0.5f); + alt = (float)body.TerrainAltitude(geo.x, geo.y, true); + cornerAlts[coords] = alt; + } + return alt; + } + + private bool CheckTraversability(Coords coords) + { + float[] cornerAlts = new float[4] + { + getCornerAlt(coords.X, coords.Y), + getCornerAlt(coords.X+1, coords.Y), + getCornerAlt(coords.X+1, coords.Y+1), + getCornerAlt(coords.X, coords.Y+1), + }; + + for (int i = 0; i < 4; i++) + { + // check if we have the correct surface on all corners (land/water) + switch (movementType) + { + case VehicleMovementType.Amphibious: + break; + + case VehicleMovementType.Land: + if (cornerAlts[i] < 0) return false; + break; + + case VehicleMovementType.Water: + if (cornerAlts[i] > MinDepth) return false; + break; + + case VehicleMovementType.Stationary: + default: + return false; + } + // set max to zero for slope check + if (cornerAlts[i] < 0) cornerAlts[i] = 0; + } + + // check if angles are not too steep (if it's a land vehicle) + if ((movementType & VehicleMovementType.Land) == VehicleMovementType.Land + && (checkSlope(cornerAlts[0], cornerAlts[1], GridSize) + || checkSlope(cornerAlts[1], cornerAlts[2], GridSize) + || checkSlope(cornerAlts[2], cornerAlts[3], GridSize) + || checkSlope(cornerAlts[3], cornerAlts[0], GridSize) + || checkSlope(cornerAlts[0], cornerAlts[2], GridDiagonal) + || checkSlope(cornerAlts[1], cornerAlts[3], GridDiagonal))) + return false; + + return true; + } + + bool checkSlope(float alt1, float alt2, float length) => Mathf.Abs(Mathf.Atan2(alt1 - alt2, length)) > maxSlopeAngle; + + public void DrawDebug(Vector3 currentWorldPos, List waypoints = null) + { + Vector3 upVec = VectorUtils.GetUpDirection(currentWorldPos) * 10; + if (BDArmorySettings.DISPLAY_PATHING_GRID) + using (var kvp = grid.GetEnumerator()) + while (kvp.MoveNext()) + { + BDGUIUtils.DrawLineBetweenWorldPositions(kvp.Current.Value.WorldPos, kvp.Current.Value.WorldPos + upVec, 3, + kvp.Current.Value.Traversable ? Color.green : Color.red); + } + if (waypoints != null) + { + var previous = currentWorldPos; + using (var wp = waypoints.GetEnumerator()) + while (wp.MoveNext()) + { + var c = VectorUtils.GetWorldSurfacePostion(wp.Current, body); + BDGUIUtils.DrawLineBetweenWorldPositions(previous + upVec, c + upVec, 2, Color.cyan); + previous = c; + } + } + } + } + } +} diff --git a/BDArmory/Control/BDACompetitionMode.cs b/BDArmory/Control/BDACompetitionMode.cs new file mode 100644 index 000000000..c5251f761 --- /dev/null +++ b/BDArmory/Control/BDACompetitionMode.cs @@ -0,0 +1,215 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Misc; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Control +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class BDACompetitionMode : MonoBehaviour + { + public static BDACompetitionMode Instance; + + void Awake() + { + if (Instance) + { + Destroy(Instance); + } + + Instance = this; + } + + void OnGUI() + { + if (competitionStarting) + { + GUIStyle cStyle = new GUIStyle(BDArmorySetup.BDGuiSkin.label); + cStyle.fontStyle = FontStyle.Bold; + cStyle.fontSize = 22; + cStyle.alignment = TextAnchor.UpperCenter; + Rect cLabelRect = new Rect(0, Screen.height / 6, Screen.width, 100); + + GUIStyle cShadowStyle = new GUIStyle(cStyle); + Rect cShadowRect = new Rect(cLabelRect); + cShadowRect.x += 2; + cShadowRect.y += 2; + cShadowStyle.normal.textColor = new Color(0, 0, 0, 0.75f); + + GUI.Label(cShadowRect, competitionStatus, cShadowStyle); + GUI.Label(cLabelRect, competitionStatus, cStyle); + } + } + + //Competition mode + public bool competitionStarting; + string competitionStatus = ""; + Coroutine competitionRoutine; + + public void StartCompetitionMode(float distance) + { + if (!competitionStarting) + { + competitionRoutine = StartCoroutine(DogfightCompetitionModeRoutine(distance)); + } + } + + public void StopCompetition() + { + if (competitionRoutine != null) + { + StopCoroutine(competitionRoutine); + } + + competitionStarting = false; + } + + IEnumerator DogfightCompetitionModeRoutine(float distance) + { + competitionStarting = true; + competitionStatus = "Competition: Pilots are taking off."; + var pilots = new Dictionary>(); + using (var loadedVessels = BDATargetManager.LoadedVessels.GetEnumerator()) + while (loadedVessels.MoveNext()) + { + if (loadedVessels.Current == null || !loadedVessels.Current.loaded) + continue; + IBDAIControl pilot = loadedVessels.Current.FindPartModuleImplementing(); + if (pilot == null || !pilot.weaponManager || pilot.weaponManager.Team.Neutral) + continue; + + if (!pilots.TryGetValue(pilot.weaponManager.Team, out List teamPilots)) + { + teamPilots = new List(); + pilots.Add(pilot.weaponManager.Team, teamPilots); + } + teamPilots.Add(pilot); + pilot.CommandTakeOff(); + if (pilot.weaponManager.guardMode) + { + pilot.weaponManager.ToggleGuardMode(); + } + } + + //clear target database so pilots don't attack yet + BDATargetManager.ClearDatabase(); + + if (pilots.Count < 2) + { + Debug.Log("[BDArmory]: Unable to start competition mode - one or more teams is empty"); + competitionStatus = "Competition: Failed! One or more teams is empty."; + yield return new WaitForSeconds(2); + competitionStarting = false; + yield break; + } + + var leaders = new List(); + using (var pilotList = pilots.GetEnumerator()) + while (pilotList.MoveNext()) + { + leaders.Add(pilotList.Current.Value[0]); + pilotList.Current.Value[0].weaponManager.wingCommander.CommandAllFollow(); + } + + //wait till the leaders are ready to engage (airborne for PilotAI) + bool ready = false; + while (!ready) + { + ready = true; + using (var leader = leaders.GetEnumerator()) + while (leader.MoveNext()) + if (leader.Current != null && !leader.Current.CanEngage()) + { + ready = false; + yield return null; + break; + } + } + + using (var leader = leaders.GetEnumerator()) + while (leader.MoveNext()) + if (leader.Current == null) + StopCompetition(); + + competitionStatus = "Competition: Sending pilots to start position."; + Vector3 center = Vector3.zero; + using (var leader = leaders.GetEnumerator()) + while (leader.MoveNext()) + center += leader.Current.vessel.CoM; + center /= leaders.Count; + Vector3 startDirection = Vector3.ProjectOnPlane(leaders[0].vessel.CoM - center, VectorUtils.GetUpDirection(center)).normalized; + startDirection *= (distance * leaders.Count / 4) + 1250f; + Quaternion directionStep = Quaternion.AngleAxis(360f / leaders.Count, VectorUtils.GetUpDirection(center)); + + for (var i = 0; i < leaders.Count; ++i) + { + leaders[i].CommandFlyTo(VectorUtils.WorldPositionToGeoCoords(startDirection, FlightGlobals.currentMainBody)); + startDirection = directionStep * startDirection; + } + + Vector3 centerGPS = VectorUtils.WorldPositionToGeoCoords(center, FlightGlobals.currentMainBody); + + //wait till everyone is in position + competitionStatus = "Competition: Waiting for teams to get in position."; + bool waiting = true; + var sqrDistance = distance * distance; + while (waiting) + { + waiting = false; + + using (var leader = leaders.GetEnumerator()) + while (leader.MoveNext()) + { + if (leader.Current == null) + StopCompetition(); + + using (var otherLeader = leaders.GetEnumerator()) + while (otherLeader.MoveNext()) + { + if (leader.Current == otherLeader.Current) + continue; + if ((leader.Current.transform.position - otherLeader.Current.transform.position).sqrMagnitude < sqrDistance) + waiting = true; + } + + // Increase the distance for large teams + var sqrTeamDistance = (800 + 100 * pilots[leader.Current.weaponManager.Team].Count) * (800 + 100 * pilots[leader.Current.weaponManager.Team].Count); + using (var pilot = pilots[leader.Current.weaponManager.Team].GetEnumerator()) + while (pilot.MoveNext()) + if (pilot.Current != null + && pilot.Current.currentCommand == PilotCommands.Follow + && (pilot.Current.vessel.CoM - pilot.Current.commandLeader.vessel.CoM).sqrMagnitude > 1000f * 1000f) + waiting = true; + + if (waiting) break; + } + + yield return null; + } + + //start the match + using (var teamPilots = pilots.GetEnumerator()) + while (teamPilots.MoveNext()) + using (var pilot = teamPilots.Current.Value.GetEnumerator()) + while (pilot.MoveNext()) + { + if (pilot.Current == null) continue; + + if (!pilot.Current.weaponManager.guardMode) + pilot.Current.weaponManager.ToggleGuardMode(); + + using (var leader = leaders.GetEnumerator()) + while (leader.MoveNext()) + BDATargetManager.ReportVessel(pilot.Current.vessel, leader.Current.weaponManager); + + pilot.Current.ReleaseCommand(); + pilot.Current.CommandAttack(centerGPS); + } + + competitionStatus = "Competition starting! Good luck!"; + yield return new WaitForSeconds(2); + competitionStarting = false; + } + } +} diff --git a/BDArmory/Control/BDAirspeedControl.cs b/BDArmory/Control/BDAirspeedControl.cs new file mode 100644 index 000000000..b37c73df6 --- /dev/null +++ b/BDArmory/Control/BDAirspeedControl.cs @@ -0,0 +1,252 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace BDArmory.Control +{ + public class BDAirspeedControl : MonoBehaviour //: PartModule + { + //[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = false, guiName = "TargetSpeed"), + // UI_FloatRange(minValue = 1f, maxValue = 420f, stepIncrement = 1f, scene = UI_Scene.All)] + public float targetSpeed = 0; + + public bool useBrakes = true; + public bool allowAfterburner = true; + + //[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = false, guiName = "ThrottleFactor"), + // UI_FloatRange(minValue = 1f, maxValue = 20f, stepIncrement = .5f, scene = UI_Scene.All)] + public float throttleFactor = 2f; + + public Vessel vessel; + + bool controlEnabled; + + //[KSPField(guiActive = true, guiName = "Thrust")] + public float debugThrust; + + List multiModeEngines; + + //[KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "ToggleAC")] + public void Toggle() + { + if (controlEnabled) + { + Deactivate(); + } + else + { + Activate(); + } + } + + public void Activate() + { + controlEnabled = true; + vessel.OnFlyByWire -= AirspeedControl; + vessel.OnFlyByWire += AirspeedControl; + multiModeEngines = new List(); + } + + public void Deactivate() + { + controlEnabled = false; + vessel.OnFlyByWire -= AirspeedControl; + } + + void AirspeedControl(FlightCtrlState s) + { + if (targetSpeed == 0) + { + if (useBrakes) + vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); + s.mainThrottle = 0; + return; + } + + float currentSpeed = (float)vessel.srfSpeed; + float speedError = targetSpeed - currentSpeed; + + float setAccel = speedError * throttleFactor; + + SetAcceleration(setAccel, s); + } + + void SetAcceleration(float accel, FlightCtrlState s) + { + float gravAccel = GravAccel(); + float requestEngineAccel = accel - gravAccel; + + possibleAccel = gravAccel; + + float dragAccel = 0; + float engineAccel = MaxEngineAccel(requestEngineAccel, out dragAccel); + + if (engineAccel == 0) + { + s.mainThrottle = accel > 0 ? 1 : 0; + return; + } + + requestEngineAccel = Mathf.Clamp(requestEngineAccel, -engineAccel, engineAccel); + + float requestThrottle = (requestEngineAccel - dragAccel) / engineAccel; + + s.mainThrottle = Mathf.Clamp01(requestThrottle); + + //use brakes if overspeeding too much + if (useBrakes) + { + if (requestThrottle < -0.5f) + { + vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); + } + else + { + vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, false); + } + } + } + + float MaxEngineAccel(float requestAccel, out float dragAccel) + { + float maxThrust = 0; + float finalThrust = 0; + multiModeEngines.Clear(); + + List.Enumerator engines = vessel.FindPartModulesImplementing().GetEnumerator(); + while (engines.MoveNext()) + { + if (engines.Current == null) continue; + if (!engines.Current.EngineIgnited) continue; + + MultiModeEngine mme = engines.Current.part.FindModuleImplementing(); + if (IsAfterBurnerEngine(mme)) + { + multiModeEngines.Add(mme); + mme.autoSwitch = false; + } + + if (mme && mme.mode != engines.Current.engineID) continue; + float engineThrust = engines.Current.maxThrust; + if (engines.Current.atmChangeFlow) + { + engineThrust *= engines.Current.flowMultiplier; + } + maxThrust += engineThrust * (engines.Current.thrustPercentage / 100f); + + finalThrust += engines.Current.finalThrust; + } + engines.Dispose(); + + debugThrust = maxThrust; + + float vesselMass = vessel.GetTotalMass(); + + float accel = maxThrust / vesselMass; + + //estimate drag + float estimatedCurrentAccel = finalThrust / vesselMass - GravAccel(); + Vector3 vesselAccelProjected = Vector3.Project(vessel.acceleration_immediate, vessel.velocityD.normalized); + float actualCurrentAccel = vesselAccelProjected.magnitude * Mathf.Sign(Vector3.Dot(vesselAccelProjected, vessel.velocityD.normalized)); + float accelError = (actualCurrentAccel - estimatedCurrentAccel); // /2 -- why divide by 2 here? + dragAccel = accelError; + + possibleAccel += accel; + + //use multimode afterburner for extra accel if lacking + List.Enumerator mmes = multiModeEngines.GetEnumerator(); + while (mmes.MoveNext()) + { + if (mmes.Current == null) continue; + if (allowAfterburner && accel < requestAccel * 0.2f) + { + if (mmes.Current.runningPrimary) + { + mmes.Current.Events["ModeEvent"].Invoke(); + } + } + else if (!allowAfterburner || accel > requestAccel * 1.5f) + { + if (!mmes.Current.runningPrimary) + { + mmes.Current.Events["ModeEvent"].Invoke(); + } + } + } + mmes.Dispose(); + return accel; + } + + private static bool IsAfterBurnerEngine(MultiModeEngine engine) + { + if (engine == null) + { + return false; + } + if (!engine) + { + return false; + } + return engine.primaryEngineID == "Dry" && engine.secondaryEngineID == "Wet"; + } + + float GravAccel() + { + Vector3 geeVector = FlightGlobals.getGeeForceAtPosition(vessel.CoM); + float gravAccel = geeVector.magnitude * Mathf.Cos(Mathf.Deg2Rad * Vector3.Angle(-geeVector, vessel.velocityD)); + return gravAccel; + } + + float possibleAccel; + + public float GetPossibleAccel() + { + return possibleAccel; + } + } + + public class BDLandSpeedControl : MonoBehaviour + { + public float targetSpeed; + public Vessel vessel; + public bool preventNegativeZeroPoint = false; + + private float lastThrottle; + public float zeroPoint { get; private set; } + + private const float gain = 0.5f; + private const float zeroMult = 0.02f; + + public void Activate() + { + vessel.OnFlyByWire -= SpeedControl; + vessel.OnFlyByWire += SpeedControl; + zeroPoint = 0; + lastThrottle = 0; + } + + public void Deactivate() + { + vessel.OnFlyByWire -= SpeedControl; + } + + void SpeedControl(FlightCtrlState s) + { + if (!vessel.LandedOrSplashed) + s.wheelThrottle = 0; + else if (targetSpeed == 0) + { + vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); + s.wheelThrottle = 0; + } + else + { + float throttle = zeroPoint + (targetSpeed - (float)vessel.srfSpeed) * gain; + lastThrottle = Mathf.Clamp(throttle, -1, 1); + zeroPoint = (zeroPoint + lastThrottle * zeroMult) * (1 - zeroMult); + if (preventNegativeZeroPoint && zeroPoint < 0) zeroPoint = 0; + s.wheelThrottle = lastThrottle; + vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, throttle < -5f); + } + } + } +} diff --git a/BDArmory/Control/IBDAIControl.cs b/BDArmory/Control/IBDAIControl.cs new file mode 100644 index 000000000..3701c0af8 --- /dev/null +++ b/BDArmory/Control/IBDAIControl.cs @@ -0,0 +1,69 @@ +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Control +{ + public interface IBDAIControl + { + #region PartModule + + Vessel vessel { get; } + Transform transform { get; } + + #endregion PartModule + + /// + /// The weapon manager the AI connects to. + /// + MissileFire weaponManager { get; } + + void ActivatePilot(); + + void DeactivatePilot(); + + void TogglePilot(); + + bool pilotEnabled { get; } + + /// + /// A function to check if AI could possibly fire at the target with forward looking fixed weapons. + /// E.g. ships won't be able to fire at airborne targets, hot air baloons might never return true, etc. + /// + /// Vessel to be checked + /// true if the AI thinks it might eventually fire on the target with direct fire weapons, false otherwise + /// Guard mode uses this to check if fixed weapons are viable when selecting weapons. + bool IsValidFixedWeaponTarget(Vessel target); + + /// + /// Check if AI is combat-capable. + /// E.g. dogfight competition mode checks this before starting the competition. + /// + /// true if AI is ready for combat + /// Mainly use this to check for obvious user errors such as forgetting to stage engines. + bool CanEngage(); + + #region WingCommander + + string currentStatus { get; } + + void ReleaseCommand(); + + void CommandFollow(ModuleWingCommander leader, int followerIndex); + + void CommandAG(KSPActionGroup ag); + + void CommandFlyTo(Vector3 gpsCoords); + + void CommandAttack(Vector3 gpsCoords); + + void CommandTakeOff(); + + Vector3d commandGPS { get; } + PilotCommands currentCommand { get; } + ModuleWingCommander commandLeader { get; } + + #endregion WingCommander + } + + public enum PilotCommands { Free, Attack, Follow, FlyTo } +} diff --git a/BDArmory/CounterMeasure/CMChaff.cs b/BDArmory/CounterMeasure/CMChaff.cs new file mode 100644 index 000000000..4d8696b98 --- /dev/null +++ b/BDArmory/CounterMeasure/CMChaff.cs @@ -0,0 +1,66 @@ +using System.Collections; +using BDArmory.Misc; +using UnityEngine; + +namespace BDArmory.CounterMeasure +{ + public class CMChaff : MonoBehaviour + { + KSPParticleEmitter pe; + + const float drag = 5; + + Vector3d geoPos; + Vector3 velocity; + CelestialBody body; + + public void Emit(Vector3 position, Vector3 velocity) + { + transform.position = position; + this.velocity = velocity; + gameObject.SetActive(true); + } + + void OnEnable() + { + if (!pe) + { + pe = gameObject.GetComponentInChildren(); + EffectBehaviour.AddParticleEmitter(pe); + } + + body = FlightGlobals.currentMainBody; + if (!body) + { + gameObject.SetActive(false); + return; + } + + StartCoroutine(LifeRoutine()); + } + + IEnumerator LifeRoutine() + { + geoPos = VectorUtils.WorldPositionToGeoCoords(transform.position, body); + + pe.EmitParticle(); + + float startTime = Time.time; + while (Time.time - startTime < pe.maxEnergy) + { + transform.position = body.GetWorldSurfacePosition(geoPos.x, geoPos.y, geoPos.z); + velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; + Vector3 dragForce = (0.008f) * drag * 0.5f * velocity.sqrMagnitude * + (float) + FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), + FlightGlobals.getExternalTemperature(), body) * velocity.normalized; + velocity -= (dragForce) * Time.fixedDeltaTime; + transform.position += velocity * Time.fixedDeltaTime; + geoPos = VectorUtils.WorldPositionToGeoCoords(transform.position, body); + yield return new WaitForFixedUpdate(); + } + + gameObject.SetActive(false); + } + } +} diff --git a/BDArmory/CounterMeasure/CMDropper.cs b/BDArmory/CounterMeasure/CMDropper.cs new file mode 100644 index 000000000..557cecfc9 --- /dev/null +++ b/BDArmory/CounterMeasure/CMDropper.cs @@ -0,0 +1,340 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using BDArmory.Core; +using BDArmory.Misc; +using BDArmory.UI; +using UniLinq; +using UnityEngine; + +namespace BDArmory.CounterMeasure +{ + public class CMDropper : PartModule + { + public static ObjectPool flarePool; + public static ObjectPool chaffPool; + public static ObjectPool smokePool; + + public enum CountermeasureTypes + { + Flare, + Chaff, + Smoke + } + + public CountermeasureTypes cmType = CountermeasureTypes.Flare; + [KSPField] public string countermeasureType = "flare"; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_EjectVelocity"),//Eject Velocity + UI_FloatRange(controlEnabled = true, scene = UI_Scene.Editor, minValue = 1f, maxValue = 200f, stepIncrement = 1f)] + public float ejectVelocity = 30; + + [KSPField] public string ejectTransformName; + Transform ejectTransform; + + [KSPField] public string effectsTransformName = string.Empty; + Transform effectsTransform; + + AudioSource audioSource; + AudioClip cmSound; + AudioClip smokePoofSound; + + string resourceName; + + VesselChaffInfo vci; + + [KSPAction("Fire Countermeasure")] + public void AGDropCM(KSPActionParam param) + { + DropCM(); + } + + [KSPEvent(guiActive = true, guiName = "#LOC_BDArmory_FireCountermeasure", active = true)]//Fire Countermeasure + public void DropCM() + { + switch (cmType) + { + case CountermeasureTypes.Flare: + DropFlare(); + break; + + case CountermeasureTypes.Chaff: + DropChaff(); + break; + + case CountermeasureTypes.Smoke: + PopSmoke(); + break; + } + } + + public override void OnStart(StartState state) + { + if (HighLogic.LoadedSceneIsFlight) + { + SetupCM(); + + ejectTransform = part.FindModelTransform(ejectTransformName); + + if (effectsTransformName != string.Empty) + { + effectsTransform = part.FindModelTransform(effectsTransformName); + } + + part.force_activate(); + + audioSource = gameObject.AddComponent(); + audioSource.minDistance = 1; + audioSource.maxDistance = 1000; + audioSource.spatialBlend = 1; + + UpdateVolume(); + BDArmorySetup.OnVolumeChange += UpdateVolume; + } + else + { + SetupCMType(); + Fields["ejectVelocity"].guiActiveEditor = cmType != CountermeasureTypes.Smoke; + } + } + + void UpdateVolume() + { + if (audioSource) + { + audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + } + + void OnDestroy() + { + BDArmorySetup.OnVolumeChange -= UpdateVolume; + } + + public override void OnUpdate() + { + if (audioSource) + { + if (vessel.isActiveVessel) + { + audioSource.dopplerLevel = 0; + } + else + { + audioSource.dopplerLevel = 1; + } + } + } + + void FireParticleEffects() + { + if (!effectsTransform) return; + IEnumerator pe = effectsTransform.gameObject.GetComponentsInChildren().Cast().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + EffectBehaviour.AddParticleEmitter(pe.Current); + pe.Current.Emit(); + } + pe.Dispose(); + } + + PartResource GetCMResource() + { + IEnumerator res = part.Resources.GetEnumerator(); + while (res.MoveNext()) + { + if (res.Current == null) continue; + if (res.Current.resourceName == resourceName) return res.Current; + } + res.Dispose(); + return null; + } + + void SetupCMType() + { + countermeasureType = countermeasureType.ToLower(); + switch (countermeasureType) + { + case "flare": + cmType = CountermeasureTypes.Flare; + break; + + case "chaff": + cmType = CountermeasureTypes.Chaff; + break; + + case "smoke": + cmType = CountermeasureTypes.Smoke; + break; + } + } + + void SetupCM() + { + countermeasureType = countermeasureType.ToLower(); + switch (countermeasureType) + { + case "flare": + cmType = CountermeasureTypes.Flare; + cmSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/flareSound"); + if (!flarePool) + { + SetupFlarePool(); + } + resourceName = "CMFlare"; + break; + + case "chaff": + cmType = CountermeasureTypes.Chaff; + cmSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/smokeEject"); + resourceName = "CMChaff"; + vci = vessel.gameObject.GetComponent(); + if (!vci) + { + vci = vessel.gameObject.AddComponent(); + } + if (!chaffPool) + { + SetupChaffPool(); + } + break; + + case "smoke": + cmType = CountermeasureTypes.Smoke; + cmSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/smokeEject"); + smokePoofSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/smokePoof"); + resourceName = "CMSmoke"; + if (smokePool == null) + { + SetupSmokePool(); + } + break; + } + } + + void DropFlare() + { + PartResource cmResource = GetCMResource(); + if (cmResource == null || !(cmResource.amount >= 1)) return; + cmResource.amount--; + audioSource.pitch = UnityEngine.Random.Range(0.9f, 1.1f); + audioSource.PlayOneShot(cmSound); + + GameObject cm = flarePool.GetPooledObject(); + cm.transform.position = transform.position; + CMFlare cmf = cm.GetComponent(); + cmf.velocity = part.rb.velocity + + Krakensbane.GetFrameVelocityV3f() + + (ejectVelocity * transform.up) + + (UnityEngine.Random.Range(-3f, 3f) * transform.forward) + + (UnityEngine.Random.Range(-3f, 3f) * transform.right); + cmf.SetThermal(vessel); + + cm.SetActive(true); + + FireParticleEffects(); + } + + void DropChaff() + { + PartResource cmResource = GetCMResource(); + if (cmResource == null || !(cmResource.amount >= 1)) return; + cmResource.amount--; + audioSource.pitch = UnityEngine.Random.Range(0.9f, 1.1f); + audioSource.PlayOneShot(cmSound); + + if (!vci) + { + vci = vessel.gameObject.AddComponent(); + } + vci.Chaff(); + + GameObject cm = chaffPool.GetPooledObject(); + CMChaff chaff = cm.GetComponent(); + chaff.Emit(ejectTransform.position, ejectVelocity * ejectTransform.forward); + + FireParticleEffects(); + } + + void PopSmoke() + { + PartResource smokeResource = GetCMResource(); + if (smokeResource.amount >= 1) + { + smokeResource.amount--; + audioSource.pitch = UnityEngine.Random.Range(0.9f, 1.1f); + audioSource.PlayOneShot(cmSound); + + StartCoroutine(SmokeRoutine()); + + FireParticleEffects(); + } + } + + IEnumerator SmokeRoutine() + { + yield return new WaitForSeconds(0.2f); + GameObject smokeCMObject = smokePool.GetPooledObject(); + CMSmoke smoke = smokeCMObject.GetComponent(); + smoke.velocity = part.rb.velocity + (ejectVelocity * transform.up) + + (UnityEngine.Random.Range(-3f, 3f) * transform.forward) + + (UnityEngine.Random.Range(-3f, 3f) * transform.right); + smokeCMObject.SetActive(true); + smokeCMObject.transform.position = ejectTransform.position + (10 * ejectTransform.forward); + float longestLife = 0; + IEnumerator emitter = smokeCMObject.GetComponentsInChildren().Cast().GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + EffectBehaviour.AddParticleEmitter(emitter.Current); + emitter.Current.Emit(); + if (emitter.Current.maxEnergy > longestLife) longestLife = emitter.Current.maxEnergy; + } + emitter.Dispose(); + + audioSource.PlayOneShot(smokePoofSound); + yield return new WaitForSeconds(longestLife); + smokeCMObject.SetActive(false); + } + + void SetupFlarePool() + { + GameObject cm = (GameObject)Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/CMFlare/model")); + cm.SetActive(false); + cm.AddComponent(); + flarePool = ObjectPool.CreateObjectPool(cm, 10, true, true); + } + + void SetupSmokePool() + { + GameObject cm = + (GameObject)Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/CMSmoke/cmSmokeModel")); + cm.SetActive(false); + cm.AddComponent(); + + smokePool = ObjectPool.CreateObjectPool(cm, 10, true, true); + } + + void SetupChaffPool() + { + GameObject cm = (GameObject)Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/CMChaff/model")); + cm.SetActive(false); + cm.AddComponent(); + + chaffPool = ObjectPool.CreateObjectPool(cm, 10, true, true); + } + + // RMB info in editor + public override string GetInfo() + { + StringBuilder output = new StringBuilder(); + output.Append(Environment.NewLine); + output.Append($"Countermeasure: {countermeasureType}"); + output.Append(Environment.NewLine); + + return output.ToString(); + } + } +} diff --git a/BDArmory/CounterMeasure/CMFlare.cs b/BDArmory/CounterMeasure/CMFlare.cs new file mode 100644 index 000000000..298181a8b --- /dev/null +++ b/BDArmory/CounterMeasure/CMFlare.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using BDArmory.FX; +using BDArmory.Misc; +using BDArmory.UI; +using UniLinq; +using UnityEngine; + +namespace BDArmory.CounterMeasure +{ + public class CMFlare : MonoBehaviour + { + List pEmitters; // = new List(); + List gaplessEmitters; // = new List(); + + Light[] lights; + float startTime; + + public bool alive = true; + + Vector3 upDirection; + + public Vector3 velocity; + + public float thermal; //heat value + float minThermal; + float startThermal; + + float lifeTime = 5; + + public void SetThermal(Vessel sourceVessel) + { + // OLD: + //thermal = BDArmorySetup.FLARE_THERMAL*UnityEngine.Random.Range(0.45f, 1.25f); + // NEW: generate flare within spectrum of emitting vessel's heat signature + thermal = BDATargetManager.GetVesselHeatSignature(sourceVessel) * UnityEngine.Random.Range(0.65f, 1.75f); + } + + void OnEnable() + { + startThermal = thermal; + minThermal = startThermal * 0.3f; + + if (gaplessEmitters == null || pEmitters == null) + { + gaplessEmitters = new List(); + + pEmitters = new List(); + + IEnumerator pe = gameObject.GetComponentsInChildren().Cast().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + if (pe.Current.useWorldSpace) + { + BDAGaplessParticleEmitter gpe = pe.Current.gameObject.AddComponent(); + gaplessEmitters.Add(gpe); + gpe.emit = true; + } + else + { + EffectBehaviour.AddParticleEmitter(pe.Current); + pEmitters.Add(pe.Current); + pe.Current.emit = true; + } + } + pe.Dispose(); + } + List.Enumerator gEmitter = gaplessEmitters.GetEnumerator(); + while (gEmitter.MoveNext()) + { + if (gEmitter.Current == null) continue; + gEmitter.Current.emit = true; + } + gEmitter.Dispose(); + + List.Enumerator pEmitter = pEmitters.GetEnumerator(); + while (pEmitter.MoveNext()) + { + if (pEmitter.Current == null) continue; + pEmitter.Current.emit = true; + } + pEmitter.Dispose(); + + BDArmorySetup.numberOfParticleEmitters++; + + if (lights == null) + { + lights = gameObject.GetComponentsInChildren(); + } + + IEnumerator lgt = lights.AsEnumerable().GetEnumerator(); + while (lgt.MoveNext()) + { + if (lgt.Current == null) continue; + lgt.Current.enabled = true; + } + lgt.Dispose(); + startTime = Time.time; + + //ksp force applier + //gameObject.AddComponent().drag = 0.4f; + + BDArmorySetup.Flares.Add(this); + + upDirection = VectorUtils.GetUpDirection(transform.position); + } + + void FixedUpdate() + { + if (!gameObject.activeInHierarchy) + { + return; + } + + //floating origin and velocity offloading corrections + if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) + { + transform.position -= FloatingOrigin.OffsetNonKrakensbane; + } + + if (velocity != Vector3.zero) + { + transform.rotation = Quaternion.LookRotation(velocity, upDirection); + } + + //Particle effects + //downforce + Vector3 downForce = (Mathf.Clamp(velocity.magnitude, 0.1f, 150) / 150) * 20 * -upDirection; + + //turbulence + List.Enumerator gEmitter = gaplessEmitters.GetEnumerator(); + while (gEmitter.MoveNext()) + { + if (gEmitter.Current == null) continue; + if (!gEmitter.Current.pEmitter) continue; + try + { + gEmitter.Current.pEmitter.worldVelocity = 2 * ParticleTurbulence.flareTurbulence + downForce; + } + catch (NullReferenceException) + { + Debug.LogWarning("CMFlare NRE setting worldVelocity"); + } + + try + { + if (FlightGlobals.ActiveVessel && FlightGlobals.ActiveVessel.atmDensity <= 0) + { + gEmitter.Current.emit = false; + } + } + catch (NullReferenceException) + { + Debug.LogWarning("CMFlare NRE checking density"); + } + } + gEmitter.Dispose(); + // + + //thermal decay + thermal = Mathf.MoveTowards(thermal, minThermal, + ((thermal - minThermal) / lifeTime) * Time.fixedDeltaTime); + + if (Time.time - startTime > lifeTime) //stop emitting after lifeTime seconds + { + alive = false; + BDArmorySetup.Flares.Remove(this); + + List.Enumerator pe = pEmitters.GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + pe.Current.emit = false; + } + pe.Dispose(); + + List.Enumerator gpe = gaplessEmitters.GetEnumerator(); + while (gpe.MoveNext()) + { + if (gpe.Current == null) continue; + gpe.Current.emit = false; + } + gpe.Dispose(); + + IEnumerator lgt = lights.AsEnumerable().GetEnumerator(); + while (lgt.MoveNext()) + { + if (lgt.Current == null) continue; + lgt.Current.enabled = false; + } + lgt.Dispose(); + } + + if (Time.time - startTime > lifeTime + 11) //disable object after x seconds + { + BDArmorySetup.numberOfParticleEmitters--; + gameObject.SetActive(false); + return; + } + + //physics + //atmospheric drag (stock) + float simSpeedSquared = velocity.sqrMagnitude; + Vector3 currPos = transform.position; + const float mass = 0.001f; + const float drag = 1f; + Vector3 dragForce = (0.008f * mass) * drag * 0.5f * simSpeedSquared * + (float) + FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), + FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody) * + velocity.normalized; + + velocity -= (dragForce / mass) * Time.fixedDeltaTime; + // + + //gravity + if (FlightGlobals.RefFrameIsRotating) + velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; + + transform.position += velocity * Time.fixedDeltaTime; + } + } +} diff --git a/BDArmory/CounterMeasure/CMSmoke.cs b/BDArmory/CounterMeasure/CMSmoke.cs new file mode 100644 index 000000000..21186cd9f --- /dev/null +++ b/BDArmory/CounterMeasure/CMSmoke.cs @@ -0,0 +1,74 @@ +using System.Collections; +using UnityEngine; + +namespace BDArmory.CounterMeasure +{ + public class CMSmoke : MonoBehaviour + { + public Vector3 velocity; + + void OnEnable() + { + StartCoroutine(SmokeRoutine()); + } + + IEnumerator SmokeRoutine() + { + yield return new WaitForSeconds(10); + + gameObject.SetActive(false); + } + + void FixedUpdate() + { + //physics + //atmospheric drag (stock) + float simSpeedSquared = velocity.sqrMagnitude; + Vector3 currPos = transform.position; + float mass = 0.01f; + float drag = 5f; + Vector3 dragForce = (0.008f * mass) * drag * 0.5f * simSpeedSquared * + (float) + FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), + FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody) * + velocity.normalized; + + velocity -= (dragForce / mass) * Time.fixedDeltaTime; + // + + //gravity + if (FlightGlobals.RefFrameIsRotating) + velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; + + transform.position += velocity * Time.fixedDeltaTime; + } + + public static bool RaycastSmoke(Ray ray) + { + if (!CMDropper.smokePool) + { + return false; + } + + for (int i = 0; i < CMDropper.smokePool.size; i++) + { + Transform smokeTf = CMDropper.smokePool.GetPooledObject(i).transform; + if (smokeTf.gameObject.activeInHierarchy) + { + Plane smokePlane = new Plane((ray.origin - smokeTf.position).normalized, smokeTf.position); + float enter; + if (smokePlane.Raycast(ray, out enter)) + { + float dist = (ray.GetPoint(enter) - smokeTf.position).sqrMagnitude; + if (dist < 16 * 16) + { + return true; + } + } + } + } + + return false; + } + } +} diff --git a/BDArmory/CounterMeasure/VesselChaffInfo.cs b/BDArmory/CounterMeasure/VesselChaffInfo.cs new file mode 100644 index 000000000..62492e88c --- /dev/null +++ b/BDArmory/CounterMeasure/VesselChaffInfo.cs @@ -0,0 +1,60 @@ +using UnityEngine; + +namespace BDArmory.CounterMeasure +{ + [RequireComponent(typeof(Vessel))] + public class VesselChaffInfo : MonoBehaviour + { + Vessel vessel; + + const float chaffMax = 500; + const float chaffSubtractor = 120; + const float speedRegenMult = 0.6f; + const float minRegen = 40; + const float maxRegen = 500; + const float minMult = 0.1f; + float chaffScalar = 500; + + void Awake() + { + vessel = GetComponent(); + if (!vessel) + { + Debug.Log("[BDArmory]: VesselChaffInfo was added to an object with no vessel component"); + Destroy(this); + return; + } + + vessel.OnJustAboutToBeDestroyed += AboutToBeDestroyed; + } + + void OnDestroy() + { + if (vessel) + { + vessel.OnJustAboutToBeDestroyed -= AboutToBeDestroyed; + } + } + + void AboutToBeDestroyed() + { + Destroy(this); + } + + public float GetChaffMultiplier() + { + return Mathf.Clamp(chaffScalar / chaffMax, minMult, 1f); + } + + public void Chaff() + { + chaffScalar = Mathf.Clamp(chaffScalar - chaffSubtractor, 0, chaffMax); + } + + void FixedUpdate() + { + chaffScalar = Mathf.MoveTowards(chaffScalar, chaffMax, + Mathf.Clamp(speedRegenMult * (float)vessel.srfSpeed, minRegen, maxRegen) * Time.fixedDeltaTime); + } + } +} diff --git a/BDArmory/CounterMeasure/VesselECMJInfo.cs b/BDArmory/CounterMeasure/VesselECMJInfo.cs new file mode 100644 index 000000000..b156b22c1 --- /dev/null +++ b/BDArmory/CounterMeasure/VesselECMJInfo.cs @@ -0,0 +1,195 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.CounterMeasure +{ + [RequireComponent(typeof(Vessel))] + public class VesselECMJInfo : MonoBehaviour + { + List jammers; + public Vessel vessel; + + bool jEnabled; + + public bool jammerEnabled + { + get { return jEnabled; } + } + + float jStrength; + + public float jammerStrength + { + get { return jStrength; } + } + + float lbs; + + public float lockBreakStrength + { + get { return lbs; } + } + + float rcsr; + + public float rcsReductionFactor + { + get { return rcsr; } + } + + void Awake() + { + jammers = new List(); + vessel = GetComponent(); + + vessel.OnJustAboutToBeDestroyed += AboutToBeDestroyed; + GameEvents.onVesselCreate.Add(OnVesselCreate); + GameEvents.onPartJointBreak.Add(OnPartJointBreak); + GameEvents.onPartDie.Add(OnPartDie); + } + + void OnDestroy() + { + vessel.OnJustAboutToBeDestroyed -= AboutToBeDestroyed; + GameEvents.onVesselCreate.Remove(OnVesselCreate); + GameEvents.onPartJointBreak.Remove(OnPartJointBreak); + GameEvents.onPartDie.Remove(OnPartDie); + } + + void AboutToBeDestroyed() + { + Destroy(this); + } + + void OnPartDie(Part p = null) + { + if (gameObject.activeInHierarchy) + { + StartCoroutine(DelayedCleanJammerListRoutine()); + } + } + + void OnVesselCreate(Vessel v) + { + if (gameObject.activeInHierarchy) + { + StartCoroutine(DelayedCleanJammerListRoutine()); + } + } + + void OnPartJointBreak(PartJoint j, float breakForce) + { + if (gameObject.activeInHierarchy) + { + StartCoroutine(DelayedCleanJammerListRoutine()); + } + } + + public void AddJammer(ModuleECMJammer jammer) + { + if (!jammers.Contains(jammer)) + { + jammers.Add(jammer); + } + + UpdateJammerStrength(); + } + + public void RemoveJammer(ModuleECMJammer jammer) + { + jammers.Remove(jammer); + + UpdateJammerStrength(); + } + + void UpdateJammerStrength() + { + jEnabled = jammers.Count > 0; + + if (!jammerEnabled) + { + jStrength = 0; + } + + float totaljStrength = 0; + float totalLBstrength = 0; + float jSpamFactor = 1; + float lbreakFactor = 1; + + float rcsrTotal = 1; + float rcsrCount = 0; + + List.Enumerator jammer = jammers.GetEnumerator(); + while (jammer.MoveNext()) + { + if (jammer.Current == null) continue; + if (jammer.Current.signalSpam) + { + totaljStrength += jSpamFactor * jammer.Current.jammerStrength; + jSpamFactor *= 0.75f; + } + if (jammer.Current.lockBreaker) + { + totalLBstrength += lbreakFactor * jammer.Current.lockBreakerStrength; + lbreakFactor *= 0.65f; + } + if (jammer.Current.rcsReduction) + { + rcsrTotal *= jammer.Current.rcsReductionFactor; + rcsrCount++; + } + } + jammer.Dispose(); + + lbs = totalLBstrength; + jStrength = totaljStrength; + + if (rcsrCount > 0) + { + rcsr = Mathf.Clamp((rcsrTotal * rcsrCount), 0.0f, 1); //allow for 100% stealth (cloaking device) + } + else + { + rcsr = 1; + } + } + + public void DelayedCleanJammerList() + { + StartCoroutine(DelayedCleanJammerListRoutine()); + } + + IEnumerator DelayedCleanJammerListRoutine() + { + yield return null; + yield return null; + CleanJammerList(); + } + + void CleanJammerList() + { + vessel = GetComponent(); + + if (!vessel) + { + Destroy(this); + } + jammers.RemoveAll(j => j == null); + jammers.RemoveAll(j => j.vessel != vessel); + + List.Enumerator jam = vessel.FindPartModulesImplementing().GetEnumerator(); + while (jam.MoveNext()) + { + if (jam.Current == null) continue; + if (jam.Current.jammerEnabled) + { + AddJammer(jam.Current); + } + } + jam.Dispose(); + UpdateJammerStrength(); + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/ATM_BDArmory.cfg b/BDArmory/Distribution/GameData/BDArmory/ATM_BDArmory.cfg new file mode 100644 index 000000000..6d0775e13 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/ATM_BDArmory.cfg @@ -0,0 +1,17 @@ +ACTIVE_TEXTURE_MANAGER_CONFIG +{ + folder = BDArmory + enabled = true + + OVERRIDES + { + BDArmory/Textures/.* + { + compress = true + mipmaps = false + scale = 1 + max_size = 0 + make_not_readable = false + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Agencies/Agents.cfg b/BDArmory/Distribution/GameData/BDArmory/Agencies/Agents.cfg new file mode 100644 index 000000000..403d01b8a --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Agencies/Agents.cfg @@ -0,0 +1,17 @@ + +AGENT +{ + name = Bahamuto Dynamics + title = #loc_BDArmory_agent_title + description = #loc_BDArmory_agent_description + + logoURL = BDArmory/Agencies/BDA + logoScaledURL = BDArmory/Agencies/BDA_scaled + + // mentalities (very stern) + mentality = Commercial + mentality = Industrial + mentality = Perfectionist + mentality = Stern 1.0 + mentality = Moral 0.1 +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Agencies/BDA.png b/BDArmory/Distribution/GameData/BDArmory/Agencies/BDA.png new file mode 100644 index 000000000..96e6c420a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Agencies/BDA.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Agencies/BDA_scaled.truecolor b/BDArmory/Distribution/GameData/BDArmory/Agencies/BDA_scaled.truecolor new file mode 100644 index 000000000..3f0dc0c81 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Agencies/BDA_scaled.truecolor differ diff --git a/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_linux.bundle b/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_linux.bundle new file mode 100644 index 000000000..ef77b51c1 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_linux.bundle differ diff --git a/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_macosx.bundle b/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_macosx.bundle new file mode 100644 index 000000000..d90daf302 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_macosx.bundle differ diff --git a/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_windows.bundle b/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_windows.bundle new file mode 100644 index 000000000..0188d5c32 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/AssetBundles/bdarmoryshaders_windows.bundle differ diff --git a/BDArmory/Distribution/GameData/BDArmory/BDArmory.version b/BDArmory/Distribution/GameData/BDArmory/BDArmory.version new file mode 100644 index 000000000..e38c3f894 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/BDArmory.version @@ -0,0 +1,36 @@ +{ + "NAME":"BDArmory", + "URL":"https://github.com/PapaJoesSoup/BDArmory/raw/master/BDArmory/Distribution/GameData/BDArmory/BDArmory.version", + "DOWNLOAD":"https://github.com/PapaJoesSoup/BDArmory/releases/latest", + "GITHUB": + { + "USERNAME":"PapaJoesSoup", + "REPOSITORY":"BDArmory", + "ALLOW_PRE_RELEASE":false + }, + "VERSION": + { + "MAJOR":1, + "MINOR":3, + "PATCH":5, + "BUILD":0 + }, + "KSP_VERSION": + { + "MAJOR":1, + "MINOR":12, + "PATCH":3 + }, + "KSP_VERSION_MIN": + { + "MAJOR":1, + "MINOR":9, + "PATCH":0 + }, + "KSP_VERSION_MAX": + { + "MAJOR":1, + "MINOR":12, + "PATCH":999 + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/BulletDefs/BD_Bullets.cfg b/BDArmory/Distribution/GameData/BDArmory/BulletDefs/BD_Bullets.cfg new file mode 100644 index 000000000..d6e240102 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/BulletDefs/BD_Bullets.cfg @@ -0,0 +1,812 @@ +//////////////////////////////////////////////////////// +// Default Bullet Config - Do Not Change +//////////////////////////////////////////////////////// + +BULLET +{ + name = def // do not change this! + caliber = 30 + bulletVelocity = 1109 + bulletMass = .3880 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + //HE Bullet Values + explosive = False + tntMass = 0.001 + blastPower = 0.1 + blastHeat = 0.1 + blastRadius = 0.1 + +} + +//////////////////////////////////////////////////////// +// End Default Bullet Config +//////////////////////////////////////////////////////// + +BULLET +{ + name = 7.62x39mmBullet + caliber = 7.62 + bulletVelocity = 718 + bulletMass = 0.0965 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 7.7x56mmBullet + caliber = 7.7 + bulletVelocity = 825 + bulletMass = 0.0975 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 7.92mmBullet + caliber = 7.92 + bulletVelocity = 825 + bulletMass = 0.1 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + + +} + +BULLET +{ + name = 9mmBullet + caliber = 9 + bulletVelocity = 380 + bulletMass = 0.114 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + // RaufossMk211 + name = 12.7mmBullet + caliber = 12.7 + bulletVelocity = 915 + bulletMass = .15 + explosive = True + tntMass = .01 + blastPower = 0 + blastHeat = 0 + blastRadius = 0.01 + apBulletMod = 1 + bulletDragTypeName = AnalyticEstimate +} + +BULLET +{ + name = 12.7mmHEBullet + caliber = 12.7 + bulletVelocity = 890 + bulletMass = .16 + //HE Bullet Values + explosive = True + tntMass = .14 + blastPower = 3 + blastHeat = 5 + blastRadius = 2 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 20mmBullet + caliber = 20 + bulletVelocity = 1050 + bulletMass = 0.1101 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 20mmShortBullet + caliber = 20 + bulletVelocity = 950 + bulletMass = 0.1101 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 20x102mmBullet + caliber = 20 + bulletVelocity = 1050 + bulletMass = 0.1101 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 20x102mmHEBullet + caliber = 20 + bulletVelocity = 1050 + bulletMass = 0.1101 + //HE Bullet Values + explosive = True + tntMass = 0.0625 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + + +BULLET +{ + name = 23x115mmBullet + caliber = 23 + bulletVelocity = 720 + bulletMass = 0.1900 + //HE Bullet Values + explosive = True + tntMass = 0.2534 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 23x152mmBullet + caliber = 23 + bulletVelocity = 1020 + bulletMass = 0.19 + //HE Bullet Values + explosive = True + tntMass = 0.2534 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 25mmBullet + caliber = 25 + bulletVelocity = 1020 + bulletMass = 0.195 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 25x115mmBullet + caliber = 25 + bulletVelocity = 720 + bulletMass = 0.19 + //HE Bullet Values + explosive = True + tntMass = 0.2534 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 25x137mmBullet + caliber = 25 + bulletVelocity = 1020 + bulletMass = 0.19 + //HE Bullet Values + explosive = True + tntMass = 0.2534 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + + + +BULLET +{ + name = 30mmBullet + caliber = 30 + bulletVelocity = 1080 + bulletMass = 0.3880 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 30x165Bullet + caliber = 30 + bulletVelocity = 870 + bulletMass = 0.3880 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 30x173Bullet + caliber = 30 + bulletVelocity = 1109 + bulletMass = 0.3880 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 30x173HEBullet + caliber = 30 + bulletVelocity = 1109 + bulletMass = 0.3880 + //HE Bullet Values + explosive = True + tntMass = 0.254 + blastPower = 2 + blastHeat = 3.7 + blastRadius = 2.5 + apBulletMod = 3 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 35x228HEBullet + caliber = 35 + bulletVelocity = 1175 + bulletMass = 0.550 + //HE Bullet Values + explosive = True + tntMass = 0.440 + blastPower = 2 + blastHeat = 3.7 + blastRadius = 2.5 + apBulletMod = 3 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 40x53HEBullet + caliber = 40 + bulletVelocity = 242 + bulletMass = 0.3500 + //HE Bullet Values + explosive = True + tntMass = 0.25 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 40x311mmHEBullet + caliber = 40 + bulletVelocity = 242 + bulletMass = 0.3500 + //HE Bullet Values + explosive = True + tntMass = 0.25 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 57mmBullet + caliber = 70 + bulletVelocity = 1035 + bulletMass = 2.4 + //HE Bullet Values + explosive = True + tntMass = 1.2 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 75mmBullet + caliber = 75 + bulletVelocity = 620 + bulletMass = 6.8 + //HE Bullet Values + explosive = True + tntMass = 5.44 + blastPower = 10 + blastHeat = 10 + blastRadius = 7 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 76x636mmBullet + caliber = 62 + bulletVelocity = 915 + bulletMass = 6.8 + //HE Bullet Values + explosive = True + tntMass = 5.44 + blastPower = 9 + blastHeat = 7.7 + blastRadius = 4.5 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = TungstenBullet + caliber = 105 + bulletVelocity = 5000 + bulletMass = 1.25 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 5 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = WMDBullet + caliber = 200 + bulletVelocity = 3000 + bulletMass = 500 + //HE Bullet Values + explosive = True + tntMass = 400 + blastPower = 100 + blastHeat = 200 + blastRadius = 20 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = LaserBolt + caliber = 30 + bulletVelocity = 4000 + bulletMass = 0.125 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 90mmBullet + caliber = 90 + bulletVelocity = 850 + bulletMass = 19 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 100mmBullet + caliber = 100 + bulletVelocity = 1020 + bulletMass = 15 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + + name = 105mmBullet + caliber = 105 + bulletVelocity = 1020 + bulletMass = 19.6 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + + name = 105mmBulletAE + caliber = 105 + bulletVelocity = 1020 + bulletMass = 19.6 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + + name = 105mmBulletNI + caliber = 105 + bulletVelocity = 1020 + bulletMass = 19.6 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = NumericalIntegration + +} + +BULLET +{ + name = 105mmHEBullet + caliber = 105 + bulletVelocity = 1020 + bulletMass = 19.6 + //HE Bullet Values + explosive = True + tntMass = 15.68 + blastPower = 8 + blastHeat = 14 + blastRadius = 40 + apBulletMod = 6 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 4p5inchQFBullet + caliber = 113 + bulletVelocity = 746 + bulletMass = 29.4 + //HE Bullet Values + explosive = True + tntMass = 23.52 + blastPower = 25 + blastHeat = 35 + blastRadius = 30 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 120mmBullet + caliber = 120 + bulletVelocity = 850 + bulletMass = 12 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 6 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 120mmBulletHE + caliber = 120 + bulletVelocity = 800 + bulletMass = 19.6 + //HE Bullet Values + explosive = True + tntMass = 15.68 + blastPower = 20 + blastHeat = 30 + blastRadius = 30 + apBulletMod = 6 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 120mmBulletSabot + caliber = 120 + bulletVelocity = 1750 + bulletMass = 9 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 20 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 122mmBullet + caliber = 122 + bulletVelocity = 685 + bulletMass = 22.3 + //HE Bullet Values + explosive = True + tntMass = 17.84 + blastPower = 22 + blastHeat = 30 + blastRadius = 30 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 125mmBulletHE + caliber = 125 + bulletVelocity = 915 + bulletMass = 18.4 + //HE Bullet Values + explosive = True + tntMass = 8.5 + blastPower = 25 + blastHeat = 30 + blastRadius = 30 + apBulletMod = 6 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 125mmBulletSabot + caliber = 125 + bulletVelocity = 2050 + bulletMass = 9.52 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 20 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 130Bullet + caliber = 130 + bulletVelocity = 725 + bulletMass = 25 + //HE Bullet Values + explosive = False + tntMass = 0 + blastPower = 0 + blastHeat = 0 + blastRadius = 0 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = QF5-25Bullet + caliber = 133 + bulletVelocity = 814 + bulletMass = 36.29 + //HE Bullet Values + explosive = True + tntMass = 29 + blastPower = 6.5 + blastHeat = 12.5 + blastRadius = 18 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 155mmBullet + caliber = 155 + bulletVelocity = 563 + bulletMass = 90.7 + //HE Bullet Values + explosive = True + tntMass = 72.56 + blastPower = 27 + blastHeat = 47 + blastRadius = 42 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 203HEBullet + caliber = 203 + bulletVelocity = 607 + bulletMass = 100 + //HE Bullet Values + explosive = True + tntMass = 80 + blastPower = 35 + blastHeat = 45 + blastRadius = 30 + apBulletMod = 0 + bulletDragTypeName = AnalyticEstimate + +} + +BULLET +{ + name = 356ApBullet + caliber = 356 + bulletVelocity = 629 + bulletMass = 636 + //HE Bullet Values + explosive = True + tntMass = 508 + blastPower = 40 + blastHeat = 50 + blastRadius = 35 + apBulletMod = 6 + bulletDragTypeName = AnalyticEstimate + +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/BulletDefs/Inventory.txt b/BDArmory/Distribution/GameData/BDArmory/BulletDefs/Inventory.txt new file mode 100644 index 000000000..044e1c00b --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/BulletDefs/Inventory.txt @@ -0,0 +1,65 @@ +AMMO LIST +UniversalAmmunition + +7.62x39Ammo 7.62x39mmBullet +7.7x56Ammo 7.7x56mmBullet +7.92x57mmMauser 7.92mmBullet +9x19mmParaAmmo 9mmBullet +50CalAmmo---BDA----12.7mmBullet +20x21Ammo 20mmShortBullet +20x102Ammo---BDA----20mmBullet +20x163Ammo 20x163mmBullet +23x115Ammo 23x115mmBullet +23x152Ammo 23x152mmBullet +25x137Ammo 25x137mmBullet +30x165Ammo 30x165Bullet +30x173Ammo 30x173Bullet +30x173HEAmmo 30x173HEBullet +37mmFlaKAmmo +40x53Ammo +40x53HeAmmo 40x53HEBullet +40x311Ammo +54cmMortarShells +57x438Ammo 57mmBullet +TungstenShell TungstenBullet +75x714Ammo 75mmBullet +76x636Ammo 76x636mmBullet +76x638Ammo 76x636mmBullet +3inchShells +90mmShells 90mmBullet +100mmShells 100mmBullet +4p5inchQFShells +CannonShells 105mmBullet +105mmShells 105mmBullet +105mmHEShells 105mmHEBullet +120mmAmmo 120mmBullet +122mmQFShells 122mmBullet +130Shells +QF5-25Shell QF5-25Bullet +5/62Shell +138_140Shells +152Shells +155Shells 155mmBullet +180Shells +203Shells 203HEBullet +12inShells +356Shells +356ApAmmo 356ApBullet +380Shells +M65ShellAmmo +406mmNuclearShells +16inchShells +460Shells +Type4Rocket +ATRocket +Hades122rocket + +/////////////////////////////////// +Armor pack 1 +1x1 slope 150mm +1x1 panel 150mm +2x1 slope 150mm +2x1 panel 150mm +3x1 panel 150mm +4x1 panel 150mm +///////////////// \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/ChangeLog.txt b/BDArmory/Distribution/GameData/BDArmory/ChangeLog.txt new file mode 100644 index 000000000..7de211dd6 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/ChangeLog.txt @@ -0,0 +1,1410 @@ +v1.3.5_beta +* NEW FEATURES: + * Recompiled for KSP 1.12.3 + +v1.3.4 +* NEW FEATURES: + * Recompiled for KSP 1.9.1 +* FIXES + * Shaders compatibility for Mac / Linux + * Missiles problem regarding locking and losing lock affecting heat and radar missiles. (Thanks to TheKurgan to find the problematic commit) + +v1.3.3 +* NEW FEATURES: + * Recompiled for KSP 1.9.0 + * Localization en-us and zh-cn (Thanks to tinygrox!) +* FIXES + * Some NRE here and there. + * Fixes to Laser accuracy (Thanks to Gedas!) + * Part Categories for BDArmory is now activated by default + +v1.3.2 +* NEW FEATURES: + * Recompiled for KSP 1.8.1 + * Munition count to Weapon Manager GUI. +* ENHANCEMENTS + * Enhanced weapon selection. + * Beam-guided munition track moving targets. + * Improved camera tracking position. + * RMB info in editor. + * Ballistic guidance overhaul. Now it is possible to also select the angle of the ballistic path. + * Turret movement improved. +* FIXES + * Weapons respect engagement range. + * Dozen of NRE exceptions. + * Fix surface ai description. + * Fix turret gimbal calculation. + * Turrets with constrained yaw should freak out less when aiming behind them. + * Locatization fixes. + * Fixed torpedo produces thrust above water. #710 + * Fixed proximity fuze radius for explosive bullets. + * Fixed heat missiles missing target just after being fired. + + +v1.3.1 +* FIXES + * All parts have bulkheadProfiles - should stop bulkhead filter NREs. + * Rocket pods no longer fire StackOverflows. + +v1.3.0 +* NEW FEATURES: + * Multiple teams are now supported by BDA. + * Probably breaks ALL the existing addons. + The new property is `Team` instead of `team`. + Review all existing references and check whether the check is for the same/different team (`==`/`!=`) or enemy/ally (use `IsEnemy` and `IsFriendly`). + `TargetDatabase` and `GPSTargets` have gone private and are not guaranteed to contain all the teams anyway. + Use `TargetList` and `GPSTargetList` instead. + * Will lose existing saved GPS targets. + * Right-click the team button to customize the teams in-game. + * Ammo gauges. (thanks to @SuicidalInsanity) + * Disabled by default, enable in BDA settings. + * Editor subcategories. + * Disabled by default, enable in settings or by right clicking the category button. + * Any part specifying a `bdacategory` will be accordingly categorized. + * Other parts can be inferred from part modules. +* ENHANCEMENTS: + * Recompiled for KSP 1.7.0 + * Wing commander formation parameters can once again be configured in editor on the weapon manager. + * Improved gun ballistic estimation. + * BDA will show a small version number on weapon manager. +* FIXES + * AI pilot should now use torpedoes. + * Weapons will revert to default weapon group on blank weapon group entry. + * Missiles fired from turrets will obey drop time and decouple direction. + * Guns with air detonation (flak) should work now. (thanks to @SuicidalInsanity) + * Guard mode no longer stops firing at passed out pilots. (thanks to @SuicidalInsanity) + * Missile turrets should properly stop tracking in various circumstances. + * Gun safety should no longer prevent firing from aiming too close to self. + * Drag no longer causes bullets to speed up. + * Reloadable missile rail no longer permits reloading when out of ammo. + * Modular missiles autodestruction if missed improved + +v1.2.4 +* NEW FEATURES: + * Weapons groups - different weapons firing in parallel(thanks to @SuicidalInsanity) +* ENHANCEMENTS: + * Recompiled for KSP 1.6.0 +* FIXES + * Fixing modular missiles roll correction. + * Fixing modular missiles stage on proximity. + * Fixing Hipoints for mods like AirplanePlus #598 + +v1.2.3 +* NEW FEATURES: + * Recompiled for KSP 1.5.1 + * EC per shot for energy weapons like Rail guns. #486 + * EMP Weapons logic. + * Modular Missiles: Min speed before guidance trigger, time between stages. + * New High Explosive resource for missiles. + * New smoke model. + * Autopilot: Orbiting direction can be set. + +* ENHANCEMENTS: + * Explosive blast forces increased. + * Hitpoints rounding reduced to 100. #432 + * Missiles can be jettisoned using action group #539 + * Max detonation range for air explosive bullets increased from 3500m to 8000m. + * Autopilot improvements: pitchKi has saner values, also steering added. + * Guard mode: Better calculation of missiles away. + * Better bullet distribution. + * FX performance improved limiting number of parallel animations. + * Better checks for missile detonations. + +* FIXES + * HE bullets now do less kinetic damage after substracting HE mass + * HitPoints calculations: values remain the same between scenes + * HitPoints calculations: bigger vessels now have more sensible HP values. #477 + * Stop explosions moving across the ground + * Fixed detonation on collision #566 + * CSV parts export now show all parts + * Fixed weapons category due to localization issues. #580 + * Stage icons fixed for KSP 1.5.1 + * Some exceptions controlled + * Heat missiles will not lock friendly vessels. #586 + * Fixed issue where modular missiles were detecting themselves as enemy vessels and detonating. + * Modular Missiles: roll correction fixed. + +* BALANCE + * Bullet mass rebalance for lower calibers #515 + * No damage reductions for lower calibers #515 + * 120mm bullet improvements. +- Thanks to SpannerMoneky, Gedas-S, DoctorDavinci, Kergan, Gomker, PapaJoesSoup, TheDogKSP, Duck1998, and Fitiales for their work on this release! + +v1.2.2.2a +* FIXES +* added in missing high speed missle fix. somehow got lost in the merge migration. + +v1.2.2.2a +* FIXES +* added in missing high speed missle fix. somehow got lost in the merge migration. + +v1.2.2.2 +* Recompiled for KSP 1.4.5 + +* FIXES + *Error spam in Log when a radar is destroyed. An orphaned index was not properly being updated. + Reported in BDAc Forum post: https://forum.kerbalspaceprogram.com/index.php?/topic/155014-14x-bdarmory-continued-v1221-7102018-vessel-mover-camera-tools-bdmk22-destruction-effects-burn-together/&do=findComment&comment=3425233 + Thanks to greydragon70 for his thoughtful evaluation of BDac and issue reporting. + * Corrected an error where high speed missiles would sometimes not detonate in the correct location. + +* ENHANCEMENTS: + * Increased maximum allowable missles per target to 18, up from 6. + * Added EMP Module. Now Electromagnetic pulses exist in game that can disable electronics within the blast range. + * Added 2 new EMP equipped missiles HellFire EMP, and AIM-120 EMP. Small pulse radius but demonstrates the feature. + * Added 3 different sized EMP pulse FX, allows for additional sized pulse weapons. + * Added Reloadable Missile Rail (ModuleMissileRearm. Now missile launchers can be reloadable! + This module can be added to missile launcher designs to allow reloading. (code used with permission courtesy of @flywyx). + Requires unity based modifications, normal rails will not function as reloadable unless additional transforms are added. + * Added new standard resource High Explosive. Provides better matching of tntMass for balance. + * Added an Ammo switcher feature (no more Firespitter required) + * Added new Universal Ammo Box part that uses the new Ammo switcher feature. Old part remains for backawards compatability. + Use the new part going forward. To remove the need for FireSpitter, replace existing Ammo Box parts with the new part on existing craft. + * Improved sub categories for BDA parts. This helps with the clutter in the Editor under the BDA category. + * Removed BDACategoryModule as a result of the BDA categories refactor. + Existing craft may see a module not found warnings in the log. This will have no ill effects and can be safely ignored. + * Improved smoke effects for smoke canister launchers + * Added new Jet engine based on the J-404. Licensed from KTech. (Thanks @TheKurgan, @SpannerMonkey(SMCE) & @XOC2008!) + * Added new BDAc Test Drone MKIII craft, utilizing the new engine. + * Added engagement rules to all missiles + + +v1.2.2.1 +* FIXES + * Added bulletinfo.explosive check to GetInfo, so explosive shells now show blast radius in the part Info (RMB) section in the editor. + * Correct text errors in bullet names on some files. Not all platforms support UTF8 characters. + * (Internal) Fix file copy error in build process. + * Increase default detonation range boundaries and step increments. Git Issue #527 + * Removed : Final from entried in MM config 000000_HitpointModule.cfg. Causing race conditions with some BDA part mods + +* ENHANCEMENTS: + * Improved reload sound on M1Abrams Turret. + * Removed BDA_SLW.cfg from MM configs. Obsolete and no longer used. + * Converted all .wav sounds to .ogg (reduce DL size and in game memory footprint) + * Updated several Module info pages to reflect recent changes to ballistic mechanics + * Added a part module Info Page refresh mechanism to support settings changes that affect part Module info blocks in the editor. + * Added Jettison action to parts TweakUI in flight. Git Issue #539 + * (Internal) Some code refactoring (basic cleanup, Module reorganization) + * Deprecate the Cannon weaponType. Going forward, Ballistic should be used instead. Cannon remains (backwards compatibility), but will be eventually removed. + * (Internal) Updated build process to improve multi developer build and deployments. Simplified KSP version change dev environment build process. + +v1.2.2 +* NEW FEATURES: + * Recompiled for KSP 1.4.4. + +* ENHANCEMENTS: + * Added AN/APG-77 Air to ground radar. + +v1.2.1.4 +* FIXES + * Corrected error in Target Previous action group. Was pointing to Target Next method instead. + +* ENHANCEMENTS: + * Added mouse slewing (pointing) in the TargetCam Window. Now you can intuitively click and drag to position the target in the window. + * Added mouse scrollwheel zooming in TargetCam window. Now you can zoom in and zoom out using the mousewheel. + * Added reactive armor part module. Modders can now take advantage of a new armor type in BDAc. + * Added Wet Weapons Check module (ModuleWWC). This module will pevent submerged weapons from firing (like when a ship sinks). + The depth is user selectable. + + +v1.2.1.3 +* FIXES + * Removed 99_bdac_engagementenvelopes.cfg. This legacy file was interfering with the new tuning of some of the missiles. + +* ENHANCEMENTS: + * Added Target Next / Previous hot keys and Actions. Now you can switch targets without having to click on the Radar! + * Numerous missile tuning tweaks to improve flight profile appearances and improve config consistency. + * Add slider to adjust Eject Velocity of Chaff and flares in Editor. + * Revised Jet engine sound (much better now) + * Added configurable hot keys for VesselSwitcher Next and Previous Vessel (Defaults remain PgUp and PgDn) + * Revised Input Settings window to use a scroller. This reduces the size of the window by about half. + + +v1.2.1.2 +* FIXES + * Correct Radar display missing graphics when using low quality graphics Git Issue #516. + * Correct tracer display missing graphics when using low quality graphics. Git Issue #520. + * Correct automatic resizing of WingCommander Window + * Reintroduce BDAcUniversalAmmoBox Module Manager config file. Somehow was dropped during a merge somewhere back. + * Separate RWR operation from RWR display. RWR should be enabled at all times when a Radar is installed on craft. + - Opening and closing the RWR window now leaves RWR operation active. Git Issues 410, #411, #461 + * removed part configs for the AGM86-cruise an the RBS-15 They have been broken, and are superceded by improved weapons. + +* ENHANCEMENTS: + * Increase the limits of the Radar and RWR window scaling to allow for larger windows. + - Add min and max settings to the settings.cfg to allow user defined limits. Git Issue #521 + * Add mouse driven RWR and Radar windows resizing. Now you can intuitivly resize by mouse. Click an drag the lower right corner. + * Redesigned Targeting Cam window to incorporate all features added to the Radar window - resizing, boundary checks, mouse resize, relocate buttons + * Retune BDAc missiles to improve characteristics, performance, and balance. Tuning performed by Kergan + + +v1.2.1.1 +* NEW FEATURES: + * Added ModuleSpaceRadar. This limits use of space based radars supporting this module to outside the atmosphere. By DoctorDavinci and Kergan + * Added Air to ground versions of Air to Air radars. By SpannerMonkey(smce) + * Added new explosion effects. By SpanerMonkey(smce) + +* ENHANCEMENTS: + * Added boundary checking to all moveable windows. Now windows cannot be positioned off the screen. + * Added ability to scale Radar Warning Receiver Window. Scale persists to config file and can be changed in Settings. Git Issue #410 + * Redesigned and added ability to scale Radar Window. Scale persists to config file and can be changed in Settings. Git Issue #410 + * Added a toggle to collapse/expand the list of weapons on the Weapon Manager window. Git Issue #410 + * Increased the number of range steps in the Radar. Now can display up to 1000km by default. + * Added Dynamic range settings to Radar Display based on the max range of the radars in operation. + * Added close buttons to the upper right of some windows. Git Issue #410 + * Added option in Settings to turn off Bullet Hole Decals (may help with performance) + +* FIXES + * Cleaned up obsolete and deprecated unity method calls. + * Removed MM config 30_bdac_missiles_terminalmaneuvering.cfg. No longer used. + * Fixed radar locking in space. Git PR #517. By JRodriguez + +v1.2.1 +* NEW FEATURES: + * Recompiled for KSP 1.4.3. +* FIXES: + * Fixed model path for Flare & Chaff. Issue #512. + +v1.2.0 + +* NEW FEATURES: + * Support for Unity 2017. Icons textures fixed by PapaJoe. Thanks to @SpannerMonkey for chaff/smoke models. + * Compatibility with KSP 1.4.2. + * Surface AI: Yes, tank battles and ships battles are a reality now. Thanks to @Gedas for this major feature. + * Damage Consequences: damaged engine has reduced thrust and greater heat production. Issue #433. + +* ENHANCEMENTS: + * Cruise Guidance overhaul. + * Shaped explosions for AGM missiles. + * Chaff rebalance. + * New setting to disable terrain checks. + * New FX for missile collisions. + * Modular missile core - added option to control roll. + * HE-KV1 missile is now efficient and deadly in Space :) Thanks to Kergan. + * Weapons like cannons can fire up to their max range. (eg: a 20 km cannon can fire at 20 km) + +* FIXES: + * Drag of ammo boxes reduced. Issue #498. + * Dozens of small fixes and rebalance! + +v1.1.0 + +* NEW FEATURES: + + * Bullet decals. + * Damage consequences for engine damaged. #433 + +* ENHANCEMENTS: + + * New damage model: the new system uses hitpoints instead of temperature. + * Realism overhaul for ballistics, penetration and armor. + * Realism overhaul for explosive damage and forces. + * Improvements to Cruise Guidance. + * Option for Modular Missiles to correct Roll. + + - For more detail you can check the issue #307 and the Wiki https://github.com/PapaJoesSoup/BDArmory/wiki/ +* FIXES: + * Kerbals can be killed again + * Modular missiles are not usable without Guard mode #377 + * Standby Mode is being bypassed if there is an active radar on one of the teams #406 + * Bullet trajectories and Pilot AI should no longer be affected by vessel movement and vessel switching + + +v1.0.0 + +* NEW FEATURES: + + * Radar & Stealth, re-design of how the radar system works: + - New radar reflection shader (credit: original great idea by JR!), calculating cross section in m^2: + + allows building for stealth using angled surfaces (“scatter those pesky radar waves away!”) + + calculation is normalized so that a 1x1 structural plate directly frontally facing the radar yields a return of exactly 1 m^2 + - Redesign of the radar system, radars all have different ranges & detection performance: + + radar part configs changed, new fields (floatcurves) to define detection and lock/track performance, new field to specify ground clutter effectiveness + - New in-editor analysis window to help evaluate a craft’s cross section and performance against selectable radars + - New options for configuration of radar guided missiles in the part config: + + can now explicitly specify active seeker performance (via a FloatCurve, similar to radars) + + can now explicitly specify the static radar cross section of a missile for detection purpose + - Adjustment of the Chaff countermeasure system: more gradual effect of decoying missiles away (instead of previous “all-or-nothing”) + - Adjustment of IR missiles and flare countermeasures: simulating now more of a “imaging infrared” seeker than an old dumb seeker – to be successfully decoyed, flares have to more closely match the thermal spectrum of the part the seeker has locked on to + + * Massive improvements to ballistic missile guidance and modular missiles, ability to simulate ICBM flight paths: + - Ballistic guidance has been enhanced to allow firing missiles accurately even at distances greater than 500 km + - A new field called BallisticOverShootFactor has been added to missiles, the greater the value the further the missile will go before the terminal maneuver begins + - By default all missiles now can steer in vacuum. New field called "vacuumSteerable" can be set to false to disable this behaviour + - Auto SAS activation when the missile is fired. Before it was only activated if the parent vessel had it switched on. + - Improved the Cruise and Ballistic Guidance. Ballistic Guidance will switch to AGM guidance as soon as it reached the 50% of the distance + - Guard mode in space will consider orbiting vessels as "flying" (air targets), hence engagement of space targets is possible now + + * New dedicated sonar ping and torpedo ping sounds, courtesy of PapaJoe! + +* FIXES / ENHANCEMENTS: + + * Localization updates, including chinese localization (thanks @ACEA) + * Fixed indestructible Kerbals - weapons/explosions have effect on Kerbals again! (thanks @Designer225) + * Fixed AIPilot problem with drag estimations (thanks @RichardDastardly) + * Fix missile infinite fuel + * Fix rwr window invisible in fresh installs + * Display ranges of RWR and radar display now linked, selectable display range of radar display up to configured PRE physics max range! + * Window position saving also for vesselswitcher + * Prevent active radar missiles locking onto anything they see, now obey engagement settings + * Sonar pings and torpedos only show on RWR if vessel is splashed/submerged + * Fix guard mode "cheating" - now must have detected an enemy with radar/sonar or with visual range before it can attack it + * If a cruise missile has terminal guidance, it can be switched off (before launch) in the part action window. The missile will then be purely gps guided without engaging its terminal targeting mode + * If debug labels are enabled, upon entering the editor all bda parts & their properties (if relevant for balancing) are dumped into .csv files for convenient analysis in excel + * Complete review of all event handlers, should reduce some actual or potential nullrefs upon explosive vessel disassembly + * General performance improvements due to code refactoring + + + +v0.3.0.0 + +* New DLL Changes - Full reinstall required! +* BDArmory Core : modularization of systems and features to ease integration for other mod makers +* Performance refactor and garbage collection improvements for better memory utilization + +* New Features + + * Adding new weaponClass - SLW - Ship Launched Weapon - intended to target surface vessels (splashed) and submarines (splashed and underwater) + + * weaponClass.SLW is set by missileType torpedo or depthcharge + + * New "Sonar" Implementation - If RWRThreatTypes is Sonar will not detect flying vessels, only surface ships and submersibles + + * MAX_ACTIVE_RADAR_RANGE & MAX_ENGAGEMENT_RANGE added to settings.cfg for more control over ranged combat + + * Updated checks for Landed and Splashed to be more accurate and account for sumbersibles + + * Renamed "Ground" engagement option to "Surface" to better reflect behavior + + * MM Patches updated for engagement options and torpedo types + + * Issue Reference #201 for Sonar, RWR Types, engagement Types, torpedo targeting + + * Increased Radar Range #170 + + * Logic for Smart Targeting should correct #216 + + * fixing issue with throttle mirroring when switching vessels + + * adding gaurd mode back to editor, Solves #156 + + * Ballistic Missile guidance improvements + + * Terminal Guidance will switch back to GPS target if no radar target is found + + +* New Parts + + * Courtesy of SpannerMonkey + - BDA MK1 Sonar Pod + - Sting Ray BDA LightWeight Torpedo + +* Notes on Naval Combat Features + + * Current implementation of "Sonar" reuses the current Radar code. Future state will have dedicated windows and naming convention + * Activating a "Sonar" pod still says "Activate Radar" + * A Sonar is defined by setting the rwrThreatType = 6 + - Sonar rules + - Will only detect vessels that are underwater (> 20meters) + - Sonar will not function if vessel is in flight + - Sonar does not detect "Landed" vessels, only splashed + - Normal Radar does not detect underwater vessels, still detects "Splashed" i.e. Boats + * Engagment type "SLW" only targets underwater (submarines) and Splashed (Boats) + + +v0.2.1.2 += New features= +- New Armor Parts +- New Bullet Types and configurations to support Armor penetration + - https://github.com/PapaJoesSoup/BDArmory/wiki/Bullet-Configuration +- New Universal Ammunition parts +- Start of localization + +- SM changelog for Ammo overhaul and bullet sweep detail + • Added bulletType = to all applicable turrets Browning AN/M2 bahaOMillennium bahaM230ChainGun bahaHiddenVulcan bahaM102Howitzer bahaM1Abrams BDAcGKmk2 GoalKeeperBDAcMk1 bahaGoalKeeper bahaGau-8 bahaTurret50cal + • Merge existing BDA ammunition resource definitions with UA master list + • Merge existing BDA Bullet and shell sweep definitions with UA master list + • Created large list of all current ammunition across all weapons mods + • Defined bullet and shell sweep for most popular ammunition types , obtained max dat for large caliber marine shells + • Created universal ammo box, a cfg and texture only addition + +Assigned values to universalAmmunition supply + + +v0.2.1.1 += Fixes = +- Recompiled and fixed for KSP 1.3.0 + += New features= +- Modular Missile Guidance: + - New option to detonate an stage on proximity. + +v0.2.1.0 += Fixes = +- Problem with display of trajectories/smoke of missiles #74. +- Warhead and Procedural High Explosive cannot be detonated via Action Group #162. +- AI Pilot is unable to use Rapiers in Air Breathing mode if landed #102. +- Fixing modular missile detonation when switching. +- Fixing max static launch range for modular missiles. + +v0.2.0.0 += New features= +- Modular Missile Guidance: + A full rewrite of this part has been done. Now you can build your own missiles, define all its parameters, + even its name. And it will be used by the AI as if it was a stock BDArmory missile! + + If you want to know more about this new feature, you can download a custom part pack for procedural missiles: + https://github.com/jrodrigv/BDModularMissileParts + And read this wiki + https://github.com/jrodrigv/BDModularMissileParts/wiki/1.-Building-your-first-Modular-Missile + +- Proximity Fuse for Missiles: + A new field called "detonation distance override" has been added to missiles. + 0 by default means that it will detonate within is normal explosive radius (eg: 20 meters for AIM-120) + +- Small High Explosive Warhead can now be rescaled with TweakScale. Git issue #106 + + += Changes = +- BDALoadedVesselSwitcher has been integrated into BDArmory, it will not be a separate mod anymore. + Please delete it before installing this version. +- Physics range field and logic has been removed: + BDArmory now integrates a new mod called PhysicsRangeExtender. https://github.com/jrodrigv/PhysicsRangeExtender + Now the physics range has been extended to almost 200 km. + However, be careful with landed vessels. Even if the vessel still loaded it could be possible that the terrain beneath it's not there anymore. + + += Fixes = +- Game crashes when adjusting the Rotary Bomb Rack. Git Issue #76. +- Missile vs Missile Accuracy. Git Issue #82 +- Bomb aiming reticle not working. Git Issue #92. +- Cluster bomb explode on load. Git Issue #151 + + += Known issues = +- Problem with display of trajectories/smoke of missiles. Git Issue #74 + +v0.11.1.6 +- Fix shaders not working on Linux and Mac OS X. Git Issue #73. +- Fix bomb aimer not working. Git Issue #75. +- Fix selected weapon message missing. Git Issue #50. +- Enhancement: Allow assigning of Toggle Radar to action groups. Git Issue #58. +- Enhancement: Ground Radar use resources now. +- Enhancement: Allow the Weapon Manager to turn on the ECM when in guard mode. Git Issue #27 +- Known issues: Adjustable Rotary Bomb Rack is officially broken and it has been tagged as (BROKEN) + +v0.11.1.5 +- Ready for KSP 1.2.1 +- New feature: Bullets penetration system. +- New parts: Goalkeeper Mk1 and Mk2 - legacy textures. +- AI improvements: for air-ground missiles, prevent firing full complement at once (respect maxMissilesTarget). +- AI improvements: prevent gps guided missiles being used on air targets/incoming missiles. +- AI improvements: improve selection of AA missiles/guns against incoming missiles. +- Missile cost rebalance. + +v0.11.1.4 (not released) +- Ready for KSP 1.2 +- Shaders and asset bundle. Fixes Git issue #47 and partially #48 +- Fix for weapons freezing when firing. Git Issue #49 + +v0.11.1.3beta +- Updated to be compatible with KSP 1.2. (Prerelease only) +- Add window persistence. Remember where I put my windows, darn it! Git Issue #13 - Partial implementation. +- Fix reload sounds on M1Abrams and M102 parts. Git Issue #39 +- Fix missing weapon icon in staging part list. +- Fix missing reload bar next to icon. +- Fix missing heat guage next to icon. + +v0.11.1.2 +- Fix sound issue with Hydra 70. Git Issue #1 +- Fix PAC Lag issue. Git Issue #3 + +v0.11.1.1 +- Revert Assembly version back to 1.0. Some mods depend on the version number of the assembly when reflecting. + +v-0.11.1.0 +- KSP 1.1.3 compatibility update. +- Mod authorship change. Papa_Joe assumed coding support + +v0.11.0.1 += Fixes +- Fix error spam when no weapon is selected + +v0.11.0 += Compatibility = +- General compatibility for KSP 1.1 +- Loading shaders with asset bundle loader + += Fixes = +- Fix incorrect tracer width in far camera with Scatterer +- Fix short bursts when firing in barrage with trigger armed +- Fix barrage on multi-barrel weapons +- Fix particle emission force being ovewritten in explosions +- Fix possible error on airborne guard with no AI pilot + + +v0.10.4.1 += Fixes = +- Fixed landed guards not attacking AI pilots +- Fixed competition distance being clamped while editing it + +v0.10.4 += AI Improvements by ferram4 = +- AI will call for help from nearby friendlies when under fire using a new SetOverrideTarget system +- AI will try to maneuver in the vertical when turning on opponents, generally deciding whether to go up/down based on whether they are under possible threat from the current target +- AI will evade guns by trying to break in towards the threat and make themselves the most difficult target possible +- AI will try to extrapolate the motion of targets based on how long it will take them to turn around +- AI will extend somewhat further when they are set to extend, which makes it more effective in gunfights and generally results in a less steep climb when they do, so they're not as helpless. +- AI will switch to a target ahead while extending +- AI will check safety of team mates before firing +- AI more likely to take high-deflection shots +- Tweaks to g-limiting behavior + += New = +- Added Bahamuto Dynamics agency (Shuudoushi) + += Changes = +- Improved AI pilot missile avoidance +- Increased guard fire duration to 3/4 of fire interval + += Fixes = +- Removed debug entries for gun index +- Fixed radar on decoupled vessels +- Fixed TGP camera when multiple are enabled +- Fixed rate of fire for barrage firing guns faster than framerate (ferram4) +- Fixed AI pilot collision avoidance interfering with missile evasion +- Fixed GUI (reticles etc) disappearing when opening/closing map view +- Fixed GUI line displaying incorrectly when one point is behind camera + +v0.10.3.3 += New = +- Salvo/Barrage toggle for guns +- New missile exhaust effects +- Missile exhaust prefabs (for modders) + += Changes = +- Improved AI pilot aiming +- Improved AI pilot roll behavior +- Improved AI pilot 'regain energy' behavior + += Fixes = +- Fixed auto cycling active radar lock when launching missile +- Fixed gun audio when fire is stopped via weapon safety check +- Fixed gun reticle when stopped via safety check +- Fixed gap in gapless particle emitter +- Fixed incorrect acceleration calculation in pilot speed controller + +v0.10.3.2 += Changes = +- When multiple radars are linked and one loses lock, the one of the others will attempt to take over + += Fixes = +- Fix competition issues again +- Fixed radar animation on track-only radar +- Fixed fire animation on low RoF guns +- Hid debug listing of radar contacts + +v0.10.3.1 += Changes = +- Improvements to AI Pilot handling of underpowered/slow planes +- A few behaviors added to help conserve energy + += Fixes = +- Fixed issue with competition mode sometimes causing a team's setup destination to be underground +- Fixed issue with compeition modes sometimes causing two teams to never be far enough apart to start battle +- Fixed competition mode not ending on revert/scene switch +- Fixed crosshair cursor showing when switching to vessel without weaponManager +- Fixed incorrect team being displayed on weaponManager in editor +- Fixed AI Pilot rolling into bombs after dropping +- Fixed non-stop wobble of bombs in FAR +- Fixed unable to close missile turrets in editor +- Delay turret reverse deploy animation for firePauseTime to prevent closing on last missile fired (for real this time) +- AI Pilot speed controller takes thrust limiter into account for calculations + +v0.10.3 += New = +- Predictive mid-air collision avoidance for AI Pilot +- Competition mode +- Compatibility with assembly dependency +- Compatibility with BDA Vessel Switcher +- AI Pilot improvements by ferram4 +- - G-limiter +- - AoA limiter +- - Dynamic minimum altitude adjustment (plane pulls out of dive earlier if needed) + += Changes = +- Guards will reset fire cycle and switch weapons if current gun has overheated +- Optional "activeMissileOnly" (bool) in MissileTurret module +- Increased radar sensitivity +- Decreased AIM-120 and AIM-9 static launch ranges +- Increased AGM min launch ranges +- Allow guard to use beam riding type missile (TOW) +- AI will do wide scan instead of focusing on target if extending to help prevent easy kill +- AI Evasive improvements +- - Fly to beam incoming missiles detected on rwr or visually +- - Fly to break away from incoming fire (instead of flying random directions) + += Fixes = +- Disabled firing with trigger when in guard mode +- Fixed AI Pilot aiming when attempting lock with heat-seeker +- Fixed Rotary Rail symmetry and rail count persistance issues (you may need to readjust the rail on your crafts) +- Fixed guard's final launch authorization to use missile DLZ instead of arbitrary values +- Fixed incorrect screen message when guard selects "none" +- Delay turret reverse deploy animation for firePauseTime to prevent closing on last missile fired + +v0.10.2.1 += Fixes = +- Fixed typo in AGM-86C cruise missile description (should say GPS guided) +- Disabled 'Remote firing' option by default + +v0.10.2 += New = +- Adjustable Rotary bomb/missile rail +- AI Pilot guards can select and use unguided or GPS guided bombs +- Guards will open and close cargo bays as necessary for missiles/bombs (FAR users need to manually set 'cargo bay' missiles/bombs) + += Changes = +- Selecting a missile will enable all turrets containing its type, not just current missile +- No longer render cluster bomb submunitions until they are deployed +- Guards will take longer to forget about contacts if they have not been seen +- Guards will reset memory lifetime of contact if they are seen again + += Fixes = +- Fixed targeting pod stabilizing on underwater terrain instead of surface +- Fixed Take-off not working on Command Self if AIPilot is not activated +- Fixed exceptions thrown by cluster bomb, targeting camera, and wing commander +- Reduced debug log spam + +v0.10.1 += New = +- "Command self" option for wing commander + += Changes = +- Rebalanced weapon damage +- Improved AI Pilot speed management in dogfight +- Improved AI Pilot collision avoidance behavior +- Reduced bullet damage factor to 100 +- Tweaked AIM-120 aero slightly +- Increased heat of explosions +- Extra explosion heat when part is destroyed is transferred to connected part +- Factor in DMG_MULTIPLIER for explosives +- optional cannonShellHeat value for ModuleWeapon - if defined, it will be used in heat damage calculation for shell explosion +- Tweaked flare effects + += Fixes = +- Fixed WeaponManager using missiles asymmetrically +- Fixed exceptions being thrown by WingCommander in editor +- Fixed exceptions thrown by ModuleTargetingCamera during loading +- Fixed RWR not functioning if it was enabled on reload +- Fixed AI using incorrect gun distance when airborne +- Fixed AI Pilot turning incorrect direction sometimes when enemy is beyond 90deg bearing + + +v0.10.0 += New = +- Wing Commander module +- Missile launcher turrets +- Rocket launcher turret +- TOW Missile +- Beam riding missile guidance +- Guard usage of missile launcher turrets +- Weapon targeting types are displayed in weapon list +- Weapon alignment and converge distance indicator in editor (F2) +- MinCombatSpeed variable for AI Pilot, below which the pilot will focus on regaining speed when extending or orbiting +- Idle speed for AI Pilot for when it is only orbiting +- Added steer damping value for missiles to reduce oscillations +- Ripple fire settings will be saved per-weapon +- Ripple fire action group toggle +- Tweakable gun range for guards (to decide between guns or missiles) +- Tweakable missiles per target value for guards (will wait until set amount of missiles have missed before firing again) +- Support for turret rotation sound effects +- Optional radarName field to display in modules tab instead of part title +- Support for built-in radars on turrets +- New bullet/tracer shader +- Bullet tracer intervals +- Optional ejected shell collisions +- Action groups for firing guns on weapon manager and individual guns (Currently only supports Custom1-10) +- Support for simultaneous use of multiple on-board radars +- Support for simultaneous use of multiple off-board radars via data-link +- Multi-locking TWS capability on fighter-style radome + += Changes = +- Radars can detect landed/splashed targets +- Changed Oerlikon Millennium to more realistic high rate of fire burst +- New sound effects for Millennium and M230 +- Changed 30mm cannons to explosive rounds +- Tweaked AIM-9 and AIM-120 aero/steering values +- Tweaked drag and lift curves and coefficients +- Tweaked flare thermal value +- Changed PAC-3 to semi-active homing +- AI Pilot will return to and orbit the area it took off from/was activated when not in combat unless commanded to a location via wingcommander +- Improved AI Pilot throttle control and use of multi-mode engine (afterburner) +- Improved AI Pilot handling post-stall +- Improved AI Pilot evasive behavior +- Improved AI Pilot behavior for ground target gun attack +- Changed default max guard visual range to 5km +- Guard that is fixated on a target will intermittently do a wide scan to check for new threats +- Reduced weapon manager audio source ranges +- Reduced Browning AN/M2 mass to 40kg +- Missile smoke trails persist after missile is destroyed +- Improved cruise missile behavior +- Circle icon for friendly contact on B-Scope radar display + += Fixes = +- Fixed chain reactions causing rippled bombs to detonate simultaneously +- Fixed guns firing after automatically switching when emptying stores of previous missile/rocket via fire key +- Fixed empty rocket pods remaining on available weapons list +- Fixed guard mode fire intervals cycling too quickly for air-to-air missiles +- Fixed MANY guard mode issues causing it not to work properly/consistently +- Fixed incorrect selected weapon message +- Fixed targeting pod losing saved settings/target position on reload +- Fixed high relative velocity missiles stepping through objects w/o collision +- Fixed unnecessary snaking in sa or aa missile guidance +- Fixed AGM guidance on high altitude surface targets +- Fixed muzzle flashes not appearing when framerate is low +- Fixed rotary cannons not appearing to spin +- Fixed incorrect description in RBS-15 cruise missile (should say GPS guided) +- Fixed targeting pod disabling radar tracking when radar loses lock - it will wait until next lock +- Fixed turret yaw limiting behavior +- Fixed AI Pilots taking off in standby mode when peace mode is enabled +- RWR state is persistent +- Removed turret motion range tweakables from radars + += Changes by ferram4 = +- Bullet damage is now based on impact energy, not momentum +- Extra bullet damage when a part is destroyed is transferred to connected parts +- Bullet penetration is guaranteed at >~75 degrees +- Bullet ricochets are guaranteed at <~5 degrees +- Optional bullet drag (per weapon) + + No drag (legacy) + + Analytic estimate (-new default-. no affect on trajectory - only impact velocity/damage) + + Numerical Integration (affects trajectory - not accounted for by AI) + + = NOTE: aerodynamic values per weapon have not been applied yet + + +v0.9.9.1 += Changes = +- Removed WingCommander test (unfinished) + +v0.9.9 += New = +- Browning .50cal AN/M2 Fixed Gun +- Added auto proximity gun target tracking feature (currently used on fixed vulcan and browning) +- FLIR Ball Targeting Camera +- Dynamic launch zones for missiles +- DLZ display for Radar and TGP +- Guard will choose an appropriate anti-air missile depending on target distance and missile's DLZ +- AI Pilot will go evasive if it detects someone firing guns at it + += Changes = +- AI is better at trying to stay behind target +- Guard only force-enables RWR if missiles are detected (note: guard needs RWR to detect incoming radar missiles) +- Guard FOV will narrow on engaged target +- Improved and re-implemented Pilot AI launch authorization so they won't take missile shots that will obviously miss +- Added targeting info to missiles' description where it was missing + += Fixes = +- Re-enabled guard tweakables in editor +- Fixed LoadedVessels being reset when using hyperedit to place vessel +- Fixed shells being ejected in front of gun when moving +- Fixed radar window resetting when another vessel loads +- Fixed parts disappearing from BDA category after a database reload +- Removed BDA parts from utility category +- Removed 'aam' homing type from HEKV-1 (still untested) + + +v0.9.8.2 += Fixes = +- Fixed bomb simpleDrag when using FAR +- No longer removes FAR module from missiles and bombs (Handled in latest FAR update) + +v0.9.8.1 += Fix = +- Fixed persistence of Peace Mode option + +v0.9.8 += New = +- "Peace Mode" option in settings menu - guards/AI won't attack (for setting things up) + += Changes = +- Reduced radome mass +- Adjusted global drag multiplier (affects missiles) +- Improved AI Pilot steering and aiming +- Improved AI Pilot's 'extend' behavior +- Improved AI Pilot's take-off behavior +- AI Pilot will no longer fly straight up to achieve target altitude when loitering +- Guard will no longer engage target that has lost more than 75% of its mass +- Radar lock-on-after-launch is now limited to 2 re-lock-ons before failing + += Fixes = +- Missile will now remove FAR aerodynamics when launched (use BDArmory aero instead, no more double-drag) +- Fixed particle streaks when floating origin shifts +- Fixed typo in main fire key binding +- Fixed maxDeviation for all guns +- Fixed NRE's if active targeting pod is destroyed +- Fixed NRE if attempting to send gps data without weapon manager +- Fixed default drag model on bombs +- Fixed bullet spawn position on guns +- Fixed default max bullet range +- Included bullet range config value in settings.cfg +- Configured HEKV-1 for radar guidance (untested) +- Minor optimizations + +v0.9.7 += New = +- Key/button inputs for TGP and Radar +- Input binding page in settings menu +- Target selector cursor for radar when using keys/buttons +- GPS Coordinator highlights and shows name of selected target +- Off button for radar window + += Changes = +- Toolbar window face-lift and improvements +- Removed most fields/buttons from weapon manager's right-click menu +- TGP will start slewing slower then speed up - better precision +- Settings window is now draggable +- Reorganized radar buttons +- Jamming on b-scope no longer shows altitude indication (always green) +- Position of radar pings on B-scope won't update until next scan (easier to select) + += Fixes = +- Stops firing guns if clicking on RWR, data link window, or GPS window +- Fixed display of crossed-out HUD target indicator when radar-locking a friendly +- Fixed missile decouple speed not being applied to guard-fired missiles +- Fixed frame of reference for B-scope so targets in look-up or look-down situation show correct range +- Fixed position updates of attached missiles when adjusting missile rail height (caused by the extra nodes) + +v0.9.6 += New = +- TGP can be slaved to the selected GPS target +- TGP can be slaved to radar locked target +- TGP NV mode illuminates vessels + += Changes = +- Changed heat-seeker growl to slide pitch from searching to locked sound instead of two separate clips +- IVA gun audio low-pass filter frequency is now configurable in settings.cfg +- Removed redundant filter effects on lower depth TGP camera +- Tracer size updates in OnWillRenderObject instead of looping through all pooled bullets for each camera +- Stopped guard debug log entries unless DRAW_DEBUG_LABELS is enabled +- Updated laser damage (Yski) +- Guard will use long-range turrets for distant targets if no missiles available (Yski) + += Fixes = +- Fixed missing references in AIPilot causing loss of control when loading AI on standby +- Fixed incorrect calculation with CheckMiss() that caused weapons to detonate prematurely +- Fixed CheckMiss to only check no-target during post-thrust as a miss on AAM and not AGM or others +- Fixed miss not being counted in certain situations +- Fixed guard attempting to use an inactive TGP +- Fixed anti-radiation missile behavior when fired without lock, or lost lock +- Fixed TGP turret-slaving not working on non-active vessel +- Fixed turret slaving breaking when both TGP and Radar are enabled +- Fixed clicking on gui triggering a cannon reload +- Fixed turret jitter when slaved +- Fixed ABL reticle when slaved +- Fixed ABL's rendered line and physical hit point when slaved +- Max guard visual range value is read from config file (Yski) +- Removed 8km limit for PooledBullet (Yski) +- Max bullet range is read from config file (Yski) + + +v0.9.5 += New = +- GPS Coordinate lists are now persistent +- Enabled activating multiple jammers with diminishing returns for each additional jammer +- Added more stack nodes to adjustable rail +- Added configurable lock-on after launch ability for radar missiles (activation of this mode is not yet implemented though) +- Above feature also allows radar missiles which have lost surrogate radar lock to continue to predicted impact point and automatically attempt active re-lock (currently used on AMRAAM) + += Changes = +- Added variations on jamming contact's detected bearing on jammed radar +- ECM functions have been separated into configurable traits (rcs reduction, range/bearing jamming, lock-breaking) +- Made radar missile's active radar signal strength threshold configurable +- Missiles will detonate some time after they have missed +- Changed explosion damage implementation again (much better this time) +- TGP, turrets/guns, and radar will disable if vessel is not controllable + += Fixes = +- Fixed persistence of TGP locked coordinates +- Fixed jammers occasionally shutting down despite sufficient electric charge +- Vessel's jamming status is updated if parts are broken off or destroyed +- Weapon manager's module and weapon list is updated if parts are broken off or destroyed +- Fixed (harmless) debug errors when launching rockets +- Fixed rocket appearing in front of rocket launcher for one frame after launch +- Fixed possible NRE spam from ModuleWeapon after vessel loading + +v0.9.4 += New = +- Stack nodes for missiles/rockets/pods +- Stack node for AdjustableRail +- Adjustable rail will update the position of attached objects when height is adjusted (no more reattaching) + += Fixes = +- Fixed guard turrets not aiming/firing when 'visually' acquiring a target +- Fixed missile not receiving target data from weapon manager if fired via right-click menu or action group +- Fixed missiles being removed from guard's target database +- Fixed guards not engaging missiles with new targeting system + +v0.9.3 += New = +- With new targeting, guard range is instead visual range (acquire targets without sensors), limited to 3.5km +- Guard's visual scanning is a separate subroutine than the scan intervals defined by the slider (which is now just firing intervals) +- Guards can still discover and acquire targets beyond that distance by using radar or other sensors +- Guards can use Radar and TGP for turrets +- Guard's can use GPS, Laser, and Anti-radiation missiles +- Guards/AI now fire appropriate countermeasures and evade radar (via RWR) and heatseeking missiles (via visual detection) +- Guards fire both chaff and flare when a missile launch of unknown type is detected +- Guards will automatically enable radar or TGP if necessary + += Changes = +- Changed explosion damage to a new system of firing many rays in random directions using heat damage - more consistent on high-velocity impacts (may need balance tweaks) +- Anti-radiation missiles now only lock onto SAM or Detection type radars +- Bombs with any type of guidance now have the larger reticle (not just GPS) +- Improved JDAM steering +- Changed size of jammed radar ping +- Slightly increased TWR Radar scan sensitivity +- Increased missile detection for radars +- Tweaks to certain missiles' steering and aero (tweaks will continue in the future) +- Tweaked chaff effectiveness + += Fixes = +- Radar scan threshold now uses the proper configured value +- Radar-detected vessels are no longer reported to both team's target database +- Fixed debris showing up as enemy targets on radar +- Fixed some inconsistent use of TargetInfo +- Fixed rockets spawning in front of rocket pod instead of inside it + + +v0.9.2 += Changes = +- Adjusted TGP reticle sizes again +- Added reticle for where TGP is pointing when not ground stabilized + += Fixes = +- Fixed legacy targeting on GPS guided weapons +- Fixed errors in settings menu when not in-flight +- Fixed turrets not being able to fire if pitch or yaw range are locked to 0 +- Fixed ABL firing through own vessel +- Returned 'toggle' action group for guns + +v0.9.1 += New = +- Added ability to name and rename GPS coordinates (list is not yet persistant) + += Changes = +- Laser guided missile lock HUD icon slightly larger so it appears against the circular TGP HUD reticle + += Fixes = +- Fixed AIM-120 and PAC-3 aero and steering values +- Re-enabled legacy targeting for guards when legacy targeting is enabled in settings +- Fixed guard's use of turrets +- Fixed errors when getting pinged by Large Detection Radar on RWR + + +v0.9.0 += New = +- Custom BDArmory parts tab in editor +- BDArmory-specific volume sliders in options menu +- Take-off speed variable added to AI Pilot +- ModuleWeapon (replaced gun/cannon/laser functions from BahaTurret) + - Can be used without turret to simplify unity setup/part config of fixed guns + - Uses pooled bullets and ejected shells + - Improved muzzle flashes + - Center-weighted bullet spread, specified by max angle in degrees (instead of previous 'accuracy' number) +- ModuleTurret (generic turret that can be used in conjunction with other modules in the future) + - Simplified intuitive unity setup + - Independent yaw and pitch rotation speeds in degrees per second (instead of previous, inconsistent 'degrees per frame') + - Precise, instantaneous aiming, or smooth aiming, or anything in between +- New tracer texture +- Optional "shortName" for weapons + - display a short name in the weapon manager instead of the full part title +- Jettison function button for missiles/bombs/rockets +- Jettison function for WeaponManager - will jettison all selected weapon +- New Guidance mode (AGMBallistic) for more efficient air-to-surface and surface-to-surface trajectories +- Mk.83 JDAM 1000lb GPS guided bomb +- AGM-88 HARM Anti-radiation missile +- MissileLauncher module supports decoupling boosters (now used in RBS-15 boosters) +- Simulated systems + - Heat seeking + - based on temperature and heat generation + - engine occlusion can affect non-all-aspect seekers + - can lock on flares (intentionally or not) + - boresight target locking + - can be slaved to radar target for off-boresight launch + - Radar + - scan sweeps give momentary position + - some radars also show contact's velocity vector + - locking shows rapidly updating position and directional + - sends locked target info to fired missile until missile's radar goes active + - 360 degree detection radars (ground based or AWACs) and limited FoV forward facing radars (air to air targeting) + - boresight scanning for quick close-range locks in air-air combat + - data sharing + - radar cross section depends on vessel's size, shape, and rotation + - turret slaving + - scanned target info will be sent to AI's target database + - Radar Warning Receiver detecting radar sources (currently built-in with Weapon Manager) + - Anti-radiation + - When used with RWR, will show icons on detected radar sources + - Will lock on radar sources within field of view + - Targeting Pod (Camera + laser + gps) + - Laser guidance for missiles + - Turret slaving + - Lased targets can be locked by any vessel with laser guided missile + - Target GPS coordinates can be broadcast to team + - GPS + - Marked GPS coordintes are listed and shown in the HUD + - Selecting a GPS coordinate will designate it as the target and that info will be sent to GPS guided weapons on release +- Smoke countermeasures (against laser-guidance) + + += Changes = +- Settings menu is now accessible in all scenes +- Updated turrets/guns to use new modules +- Adjusted guard's priority of missiles +- Adjusted AI Pilot's missile off-boresight launch authorization angle +- Increased flare ejection speed +- Increased flare lifespan +- Upgraded flares to new heat system +- Adjusted missile aerodynamics +- Changed missile guidance behavior to drag velocity vector over target instead of pointing nose at it (modders may need to adjust steering values on custom missiles) +- Reduced texture sizes to 512x512 max + + += Fixes = +- Fixed bomb calculated impact point inaccuracy caused by stock body-lift (removed stock body lift from all missiles) +- Fixed missiles sometimes exploding instantly on attempting to fire +- Fixed issue causing cruise missiles to climb forever +- Fixed M1 Abrams' symmetry (may need to reattach on existing crafts) +- AI Pilot will no longer attempt to fire missiles when landed +- Guards will no longer detect and report hostiles that are occluded by terrain/scenery +- Fixed sight raycast test going through terrain if near it +- Settings will be saved if using Alt-B to close settings window (don't need to click save) +- Fixed looped gun audio not resetting to start position next time it's fired if had looped before +- Corrected AGM-86 name to C instead of B (B is nuclear) + +v0.8.3 += New = +- Added max speed tweakable for AI Pilot (will cut throttle and use brakes if exceeding) +- Added stand-by mode for AI Pilot +- Reload status bar and sound effect for cannons +- Added "Detonate" action group for explosive warhead + += Changes = +- Changed default AI Pilot values to commonly better settings +- Increased range of default and minimum AI Pilot altitude +- AI Pilot now tries to steer to lead target when using turret +- AI Pilot will attempt to "extend" if turning circles too long +- AI Pilot will only use rudder for stability, not for steering +- AI Pilot will initially take off at less steep angle +- Improved AI Pilot's "extend" behavior when engaging ground +- Slightly reduced missile drag again +- Adjusted PAC-3 to new lowered missile drag (won't overspeed and fail to turn) +- Greatly reduced ABL(laser) damage + += Fixes = +- Fixed input binding for fire key not working with many keys +- Reduced AI Pilot roll oscillation +- AI will no longer attempt to engage enemy missiles with their guns +- Reset target info/database entry when switching teams (fix friendly fire) +- Improved missile steering +- Fixed incorrect gimbal limit calculation by guards +- Improved turret usage by guards/AI +- Fixed guard turrets to fire at CoM instead of root +- Fixed infinite ammo to not require any resource +- Fixed laser graphical glitches + + +v0.8.2 += Changes = +- Slightly increased PAC-3 maneuverability + += Fixes = +- Made AI pilot enabled state public and persistent for contracts compatibility +- Added option to disable auto return for turrets + +v0.8.1 += New = +- PAC-3 Surface to Air Missile + += Changes = +- Slightly improved anti-air missile guidance +- Reduced AIM-120 blast radius +- Reduced missile drag +- Tweaked missile lift curve +- Slightly reduced Millennium power + += Fixes = +- Fixed default detonation range tweakable slider on turret +- Fixed inability to fire missile or rocket after firing then switching weapons +- Allowed airborne guard to use turrets at longer range if no other options + + +v0.8.0 += New = +- KSP 1.0+ compatibility +- AI Pilot Flight Computer +- Modular Missile Guidance Computer +- Oerlikon Millenium Turret (timed explosive rounds) +- Small High Explosive warhead nosecone +- Ripple firing missiles and bombs with weapon manager +- New missile aerodynamics +- Smarter guards: +- Guards now use countermeasures when fired upon +- Guards store detected target info in team's database +- Guards pick targets from team database based threat and available weapons +- Guards pick weapons based on threat +- Guards disengage if no weapons match target +- Multiple guards evenly distribute attention if multiple same-level threats +- New missile warning sounds +- New countermeasure deployment sound +- Armed weapon manager 'hold to fire' time configurable in options + += Changes = +- Slightly improved cruise missile guidance +- Rocket ripple fire RPM selector moved to weapon manager +- Improved bullet ricochet behavior on parts +- Bullets impacts that cause ricochet does less damage (angled armor helps) +- Reduced default countermeasure deflection chance +- Cannon extra ammunition box + += Fixes = +- Sidewinder texture +- Abrams attachment symmetry +- Missile navball orientation +- Smart guards set to target missiles only target missiles +- Turret returns to default position when disabled even if no deploy animation +- Fixed ugly audio caused by doppler effect when viewing missile +- Fixed stream of stray bullets when guard is firing turret at fast moving target +- Freed turret 'fire in range' limitation if any axis is limited to 0 +- other minor fixes and improvements + +v0.7.3 +- Cruise missile guidance (still needs work) +- AGM-86B Cruise Missile +- RBS-15 Cruise Missile +- Optional separate particle and sound effects for boost phase of missile +- Removed seismic charge assets (to be released separately) + +v0.7.2.1 +- Further increased packing distance leeway to fix rendezvous bug +- Merged Yskinator's laser damage model + +v0.7.2 +- 0.90 compatibility +- Fixed a severe lag/crash due to particle emitters +- Enabled Doppler effect on rocket and missile sound fx +- Dirty fix: Catch rare NRE's in explosions that cause them to explode forever +- Removed colliders from flares - they were deadly and caused framerate hit +- Particle emissions optimization for framerate +- Rockets collide with water surface +- Fixed laser's aiming reticle +- Option to disable 'Smart Guards' +- Rewrote 'vacuum missile' guidance +- Button recorder for custom fire key + +v0.7.1.1 +- Fixed AGM guidance (which I broke in 0.7.1) + +v0.7.1 +- Fixed missile instability in FAR +- Fixed some issues with using stock phys range - thanks panzer1b +- Increased weapons' impact tolerances +- Merged panzer1b's heat damage system for bullets + + +v0.7.0 +- Added Smart Guards (early) +- Added M230 Chain Gun +- Added S-8KOM Rocket Pod +- Added control authority factor to missiles based on airspeed and atmos. density +- Added bullet ricochet +- Added tweakables for turret swivel range +- Added new air-to-ground missile guidance +- Air-air missiles are inaccurate against landed units +- Tied part impact tolerance to destruction chance from explosions +- Tied damage multiplier factor to explosions +- Fix: Rocket particles cut off or taper after motor cutoff +- Fix: Increase crash tolerance of missile rail +- Fix: Limited landed pack/unpack distance to <12km to reduce vessels falling through terrain +- Fixed NRE when attempting to explode a part that is 'packed' +- Changed: Countermeasures are now a finite resource +- Changed: Greatly reduced default damage multiplier (by about 66%). +- Changed: Missiles and bombs are not explosive until they are fired. +- Changed: Explosion damage and force does not pass through objects (armor plating is more useful) +- Performance: Slightly increased trajectory simulation delta time +- Explosion models and sound effects are now configurable +- Visuals and effects tweaks +- - Improved bullet and laser textures +- - Bullet glow visible at further distances +- - Better particle trails for rockets, missiles, countermeasures + +v0.6.1.2 +- Fix: Bullets don't despawn instantly with stock phys range +- Tentative Fix: Landed vessels don't crash through terrain with large phys range setting +- Tentative Fix: Rendezvousing with vessels in orbit won't make their velocity match you on vessel load + +v0.6.1.1 +- Fix: Cluster bomb won't split if it is still ascending +- Fix: Fire prevention when mouse-over-gui only if fire key is a mouse button +- Fix: Stopped debug log spam when invalid fire key is entered. Replaced with a neat "INVALID" label in settings gui. +- Workaround: Setting physics range to 0 uses stock physics range settings again (fixes rendezvous velocity bug) + +v0.6.1 +- Added rocket launcher ripple RPM tweakable +- Added guard mode automatic weapon switching. +- Added settings option for bomb clearance detection +- Changed the way rockets spawn (they spawn in the correct slot of the pod) +- Changed rocket launcher unity setup +- Changed bullet lifetime from fixed time to physics range +- Changed toolbar icon (by sumghai) +- Fixed explosions not affecting parts if at certain angle +- Removed dependency on BDAnimationModules (rockets don't need animation anymore) +- Removed some debug stuff +- Other small fixes + +v0.6.0 +- KSP 0.25 update +- Added HEKV-1 missile (for vacuum) +- Added Mk.82 SnakeEye bomb +- Added Goalkeeper CIWS +- Added cluster bomb +- Added decouple speed and drop time tweakables to missiles/bombs +- Added action groups for toggling team, guard mode, target type to Weapon Manager +- Added bomb clearance detection +- New rocket/missile sound effects +- New explosion particle effects +- Fix: Settings (Alt-B) are persistent when saved +- Fix: Prevent firing when clicking on certain GUI elements (not all yet) +- Fix: Weapons do damage to buildings +- Fixed turret aimer problem when targeting a landed vessel +- Fixed Sidewinder collider diameter +- Fix: Missiles and guard turrets target center of mass instead of command module +- Fix: Weapon Manager part window gets refreshed when activating/deactivating guard mode +- Fix: Guard mode max range limit gets set to max physics range +- Fix: Guard mode will find new target if current target is behind cover +- Fix: Bullets fire towards fireTransforms forward(Z+) instead of pitchTransform's X+ +- Changed explosion chance to destroy part +- Slight tweak to missile guidance + +v0.5.2 +- Added aimer cursor for turrets +- Added trajectory prediction cursor for turrets, guns, rockets +- Added aim assistance (gravity, velocity compensation) +- Added Guard Mode to Weapon Manager +- Added incoming missile warning +- Added a new KSPField to configure the width of tracers +- Added turbulence effect to flares +- Changed: Increased vulcan turret pitch range +- Changed Weapon Manger "cycle" button to "previous" and "next" buttons +- Changed tracer shader to Alpha Blended +- Changed: explosion and bullets destroy parts by instantly overheating instead of explode() +- Changed: Missile turn rate and aerodynamic stability now scale with atmospheric density +- Changed: rocket aerodynamic stability now scales with atmospheric density +- Integrated guns/turrets to Weapon Manager +- Changed: switched bomb aimer to new trajectory prediction system +- Changed: missiles that acquire flares will track them instead of disabling guidance +- Bugfixes to Weapon Manager trigger behavior +- Fixed launch clamp issue? (extended floating origin threshold) +- Fixed bullet drop for different planets' gravities +- Fixed floating origin shift on flares and rockets (not perfect yet) + + +v0.5.1 +- Changed bullet trail type to LineRenderer so it will always be visible +- Changed flare particle to local space + +v0.5.0 +- Added Weapon Manager "Arming" feature +- Added target locking feature +- Added AGM-65 Maverick +- Added AIM-9 Sidewinder +- Added M102 Howitzer (AC-130 style) +- Added Fixed Hidden Vulcan +- Added RocketLauncher PartModule +- Added Hydra-70 Rocket Pod +- Added chance for explosions to destroy parts (not just push them) +- Changed bullet shader to additive particle (not blocky anymore) +- Fixed weaponManager inactive if on later stage +- Many minor tweaks + + + +v0.4.1 +- Added infinite ammo option in settings.cfg +- Added bomb aiming reticle +- Added in-game settings window (leftAlt-B) +- Added 'Camera Tools' (Numpad) +- Changed: reduced Vulcan heat-up rate +- Changed: increased m1Abrams RoF from 8 to 10rpm +- Fixed 30mm ammo box description +- Tweaked missile guidance some more +- ---missiles gradually lose lift and maneuverability after thrust cuts out +- ----this gives them a limited/optimal range +- ---missiles fired from a strafing craft behave better + +v0.4.0 +- Added Mk82 Bomb +- Added AGM-114 Hellfire Missile +- Added GAU/8 Avenger +- Added Weapon Manager part +- Added cannon shell blast power and radius config values +- Added new sound for Vulcan +- Fixed explosionFX bug (explosion would multiply by how many parts it hit) +- Added new large explosion fx for bombs +- temporarily disabled physics range extension by default +- tweaked missile guidance slightly +- increased vulcan ROF to 5500rpm + +v0.3.1 +- fixed missile guidance +- ---missile no longer drops after certain distance +- ---missile guidance works (kinda) in orbit +- missile specs now configurable +- improved missile contrail +- added missile exhaust + +v0.3.0 +- 0.24 update +- fixed: guns could shoot while in map view +- fixed: sound effects played in editor when symmetry was on +- changed tracer color default to red +- reduced ABL damage +- added tracer/laser color field in part module (R,G,B,A 0-255) +- added light effects +- added shell ejection +- added M1 Abrams cannon +- added cannon weaponType +- added AIM-120 air-to-air missile +- added custom bullet hit and explosion fx +- added settings config file +- ---fire key moved to settings.cfg +- ---instakill moved to settings.cfg +- added configurable physics range (default 15km) + + +v0.2.0 +- added 20mm Vulcan +- added "spindown animation" +- added 20x102mm ammo +- added another safety from shooting yourself +- added autolock feature +- added autoLockCapable config +- added AirBorneLaser +- added weaponType config (ballistic or laser) +- added smoke bullet hits +- fixed bug: bullet spawns far away from gun +- fixed: gun could cool to infinitely negative heat +- fixed: having multiple guns was quieter than having 1 gun +- fixed: worked while on rails timewarp +- possibly fixed: bullets and other raytraces collided with invisible stuff +- changed overheat behavior +- changed folder structure +- reduced size and mass of .50cal turret +- made unity setup a little more flexible (pitch/yaw transforms configurable) + +v0.1.1 +- added overheat behavior + sound +- added firing animation +- added bullet drop toggle + +v0.1 +- initial release of .50cal turret & ammo \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Credits.txt b/BDArmory/Distribution/GameData/BDArmory/Credits.txt new file mode 100644 index 000000000..db2c5f317 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Credits.txt @@ -0,0 +1,9 @@ +Submunition sfx by "dobroide" on freesound.org, licensed under Creative Commons Attribution 3.0 Unported (modified). +Flare sfx by "captainvince" on freesound.org, licensed under Creative Commons Attribution 3.0 Unported (modified). +http://creativecommons.org/licenses/by/3.0/ +Vulcan and gau-8 sfx credit goes to upupandaway's DCS World sound mod : http://forums.eagle.ru/showthread.php?t=106958 +Toolbar icon by sumghai. +Laser damage model and other contributions by Yski +Bullet aerodynamics and AI Pilot improvements by ferram4 +Reloadable rails code portions used with permission, courtesy of @flywyx +Portions of texture switching code in FireSpitter used by permission. See license.txt for details. \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/ColorFlareSM.png b/BDArmory/Distribution/GameData/BDArmory/FX/ColorFlareSM.png new file mode 100644 index 000000000..6b87eee04 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/ColorFlareSM.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/Torchanimation_135.png b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/Torchanimation_135.png new file mode 100644 index 000000000..441f87606 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/Torchanimation_135.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/flameA.png b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/flameA.png new file mode 100644 index 000000000..8337f5ed5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/flameA.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/flameD.png b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/flameD.png new file mode 100644 index 000000000..1e6cb2172 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/flameD.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/model.mu b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/model.mu new file mode 100644 index 000000000..3b3e751cd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/muzzleSmoke.png b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/muzzleSmoke.png new file mode 100644 index 000000000..25b51fa9c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/FlameEffect2/muzzleSmoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/PenFX.mu b/BDArmory/Distribution/GameData/BDArmory/FX/PenFX.mu new file mode 100644 index 000000000..9af334a1a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/PenFX.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/TorpWake.mu b/BDArmory/Distribution/GameData/BDArmory/FX/TorpWake.mu new file mode 100644 index 000000000..4cee584b9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/TorpWake.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/flameD.png b/BDArmory/Distribution/GameData/BDArmory/FX/flameD.png new file mode 100644 index 000000000..1e6cb2172 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/flameD.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/foam.dds b/BDArmory/Distribution/GameData/BDArmory/FX/foam.dds new file mode 100644 index 000000000..14689e2b0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/foam.dds differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/jetdriveWake.mu b/BDArmory/Distribution/GameData/BDArmory/FX/jetdriveWake.mu new file mode 100644 index 000000000..038ebf823 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/jetdriveWake.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/smoke.png b/BDArmory/Distribution/GameData/BDArmory/FX/smoke.png new file mode 100644 index 000000000..ccd100971 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/smokepuff1.png b/BDArmory/Distribution/GameData/BDArmory/FX/smokepuff1.png new file mode 100644 index 000000000..15aa331c1 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/smokepuff1.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/FX/spark.png b/BDArmory/Distribution/GameData/BDArmory/FX/spark.png new file mode 100644 index 000000000..0328ce0e7 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/FX/spark.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac addons.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac addons.ksp new file mode 100644 index 000000000..4070ae211 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac addons.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac ammunition.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac ammunition.ksp new file mode 100644 index 000000000..168cad189 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac ammunition.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac control systems.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac control systems.ksp new file mode 100644 index 000000000..0634255a0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac control systems.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac countermeasures.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac countermeasures.ksp new file mode 100644 index 000000000..133eea726 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac countermeasures.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac faq.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac faq.ksp new file mode 100644 index 000000000..04a7dd887 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac faq.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac fixed guns.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac fixed guns.ksp new file mode 100644 index 000000000..9f056c015 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac fixed guns.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac guidance types.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac guidance types.ksp new file mode 100644 index 000000000..6c74050cd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac guidance types.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac modules.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac modules.ksp new file mode 100644 index 000000000..274463a0a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac modules.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac ordinance.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac ordinance.ksp new file mode 100644 index 000000000..bcd57dd90 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac ordinance.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac radar and targeting.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac radar and targeting.ksp new file mode 100644 index 000000000..cc1e49711 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac radar and targeting.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac settings.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac settings.ksp new file mode 100644 index 000000000..9097c791c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac settings.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac turrets.ksp b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac turrets.ksp new file mode 100644 index 000000000..6f874688b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/KSPedia/bdac turrets.ksp differ diff --git a/BDArmory/Distribution/GameData/BDArmory/License.txt b/BDArmory/Distribution/GameData/BDArmory/License.txt new file mode 100644 index 000000000..f22861daa --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/License.txt @@ -0,0 +1,15 @@ +This mod for Kerbal Space Program was originally developed by Paolo Encarnacion (BahamutoD) and distributed under the license CC-BY-SA 2.0. +This mod is now being maintained in BahamutoD's absence by Joe Korinek (Papa_Joe) and continues to be distributed under the license CC-BY-SA 2.0. +Please read about the license at +https://creativecommons.org/licenses/by-sa/2.0/ +before attempting to modify and redistribute it. + +BD Armory Continued incorporates the texture switching code from Firespitter. To comply with the requirements of Firespitter's license, +the following permission notice, applicable to those parts of the code only, is included below: + +License: You may reuse code and textures from this mod, as long as you give credit in the download file and on the download post/page. +Reuse of models with permission. No reselling. No redistribution of the whole pack without permission. +UV map texture guides are included so you can re-skin to your liking. +For reuse of the plugin, please either direct people to download the dll from my official release, +OR recompile the wanted partmodule/class with a new class name to avoid conflicts. +https://github.com/snjo/Firespitter \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Localization/BDArmory.cfg b/BDArmory/Distribution/GameData/BDArmory/Localization/BDArmory.cfg new file mode 100644 index 000000000..6b7634b7c --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Localization/BDArmory.cfg @@ -0,0 +1,122 @@ +Localization +{ + en-us + { + #autoLOC_bda_1000000 = Disable Radar + #autoLOC_bda_1000001 = Enable Radar + #autoLOC_bda_1000002 = SAM + #autoLOC_bda_1000003 = FIGHTER + #autoLOC_bda_1000004 = AWACS + #autoLOC_bda_1000005 = MISSILE + #autoLOC_bda_1000006 = DETECTION + #autoLOC_bda_1000007 = UNKNOWN + #autoLOC_bda_1000008 = Radar Type: <<1>> + #autoLOC_bda_1000009 = Range: <<1>> meters + #autoLOC_bda_1000010 = RWR Threat Type: <<1>> + #autoLOC_bda_1000011 = Can Scan: <<1>> + #autoLOC_bda_1000012 = Track-While-Scan: <<1>> + #autoLOC_bda_1000013 = Can Lock: <<1>> + #autoLOC_bda_1000014 = Can Receive Data: <<1>> + #autoLOC_bda_1000015 = Simultaneous Locks: <<1>> + #autoLOC_bda_1000016 = Radar Requires EC + #autoLOC_bda_1000017 = SONAR + #autoLOC_bda_1000018 = datalink only + #autoLOC_bda_1000019 = omnidirectional + #autoLOC_bda_1000020 = boresight + #autoLOC_bda_1000021 = EC/sec: <<1>> + #autoLOC_bda_1000022 = Field of view: <<1>>° + #autoLOC_bda_1000023 = RWR Threat Type: <<1>> + #autoLOC_bda_1000024 = Capabilities: + #autoLOC_bda_1000025 = - Scanning: <<1>> + #autoLOC_bda_1000026 = - Track-While-Scan: <<1>> + #autoLOC_bda_1000027 = - Locking: <<1>> + #autoLOC_bda_1000028 = - Max Locks: <<1>> + #autoLOC_bda_1000029 = - Receive Data: <<1>> + #autoLOC_bda_1000030 = Performance: + #autoLOC_bda_1000031 = - Detection: <<1>> m^2 @ <<2>> km + #autoLOC_bda_1000032 = - Detection: (none) + #autoLOC_bda_1000033 = - Lock/Track: <<1>> m^2 @ <<2>> km + #autoLOC_bda_1000034 = - Lock/Track: (none) + #autoLOC_bda_1000035 = - Ground clutter factor: <<1>> + } + es-es + { + #autoLOC_bda_1000000 = Deshabilitar Radar + #autoLOC_bda_1000001 = Habilitar Radar + #autoLOC_bda_1000002 = MTA + #autoLOC_bda_1000003 = CAZA + #autoLOC_bda_1000004 = ATyCA + #autoLOC_bda_1000005 = MISIL + #autoLOC_bda_1000006 = DETECCIÓN + #autoLOC_bda_1000007 = DESCONOCIDO + #autoLOC_bda_1000008 = Tipo de radar: <<1>> + #autoLOC_bda_1000009 = Distancia: <<1>> metros + #autoLOC_bda_1000010 = RAR Tipo de amenaza: <<1>> + #autoLOC_bda_1000011 = Puede Escanear: <<1>> + #autoLOC_bda_1000012 = Seguir-Mientra-Escanea: <<1>> + #autoLOC_bda_1000013 = Puede Bloquear: <<1>> + #autoLOC_bda_1000014 = Puede recibir datos: <<1>> + #autoLOC_bda_1000015 = Bloqueos Simultáneos: <<1>> + #autoLOC_bda_1000016 = Radar requiere CE + } + ja + { + #autoLOC_bda_1000000 = Disable Radar + #autoLOC_bda_1000001 = Enable Radar + #autoLOC_bda_1000002 = SAM + #autoLOC_bda_1000003 = FIGHTER + #autoLOC_bda_1000004 = AWACS + #autoLOC_bda_1000005 = MISSILE + #autoLOC_bda_1000006 = DETECTION + #autoLOC_bda_1000007 = UNKNOWN + #autoLOC_bda_1000008 = Radar Type: <<1>> + #autoLOC_bda_1000009 = Range: <<1>> meters + #autoLOC_bda_1000010 = RWR Threat Type: <<1>> + #autoLOC_bda_1000011 = Can Scan: <<1>> + #autoLOC_bda_1000012 = Track-While-Scan: <<1>> + #autoLOC_bda_1000013 = Can Lock: <<1>> + #autoLOC_bda_1000014 = Can Receive Data: <<1>> + #autoLOC_bda_1000015 = Simultaneous Locks: <<1>> + #autoLOC_bda_1000016 = Radar Requires EC + } + ru + { + #autoLOC_bda_1000000 = Disable Radar + #autoLOC_bda_1000001 = Enable Radar + #autoLOC_bda_1000002 = SAM + #autoLOC_bda_1000003 = FIGHTER + #autoLOC_bda_1000004 = AWACS + #autoLOC_bda_1000005 = MISSILE + #autoLOC_bda_1000006 = DETECTION + #autoLOC_bda_1000007 = UNKNOWN + #autoLOC_bda_1000008 = Radar Type: <<1>> + #autoLOC_bda_1000009 = Range: <<1>> meters + #autoLOC_bda_1000010 = RWR Threat Type: <<1>> + #autoLOC_bda_1000011 = Can Scan: <<1>> + #autoLOC_bda_1000012 = Track-While-Scan: <<1>> + #autoLOC_bda_1000013 = Can Lock: <<1>> + #autoLOC_bda_1000014 = Can Receive Data: <<1>> + #autoLOC_bda_1000015 = Simultaneous Locks: <<1>> + #autoLOC_bda_1000016 = Radar Requires EC + } + zh-cn + { + #autoLOC_bda_1000000 = 停用雷达 + #autoLOC_bda_1000001 = 启用雷达 + #autoLOC_bda_1000002 = 防空 + #autoLOC_bda_1000003 = 机载 + #autoLOC_bda_1000004 = 预警 + #autoLOC_bda_1000005 = 导弹 + #autoLOC_bda_1000006 = 探测 + #autoLOC_bda_1000007 = 未知 + #autoLOC_bda_1000008 = 雷达类型: <<1>> + #autoLOC_bda_1000009 = 探测距离: <<1>> m + #autoLOC_bda_1000010 = 雷达特征信号类型: <<1>> + #autoLOC_bda_1000011 = 允许扫描: <<1>> + #autoLOC_bda_1000012 = 边扫描边跟踪: <<1>> + #autoLOC_bda_1000013 = 允许锁定目标: <<1>> + #autoLOC_bda_1000014 = 允许接受下行数据: <<1>> + #autoLOC_bda_1000015 = 允许锁定多个目标: <<1>> + #autoLOC_bda_1000016 = 雷达需要消耗电量 + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Localization/UI/en-us.cfg b/BDArmory/Distribution/GameData/BDArmory/Localization/UI/en-us.cfg new file mode 100644 index 000000000..7498d535f --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Localization/UI/en-us.cfg @@ -0,0 +1,266 @@ +Localization +{ + en-us + { + #LOC_BDArmory_Generic_Cancel = Cancel + #LOC_BDArmory_Generic_New = New + #LOC_BDArmory_Generic_On = On + #LOC_BDArmory_Generic_Off = Off + #LOC_BDArmory_VesselStatus_Landed = (Landed) + #LOC_BDArmory_VesselStatus_Splashed = (Splashed) + + #LOC_BDArmory_WMWindow_title = BDA Weapon Manager + #LOC_BDArmory_WMWindow_GuardModebtn = Guard Mode + #LOC_BDArmory_WMWindow_ArmedText = Trigger is\u0020 + #LOC_BDArmory_WMWindow_ArmedText_ARMED = ARMED. + #LOC_BDArmory_WMWindow_ArmedText_DisArmed = disarmed. + #LOC_BDArmory_WMWindow_TeamText = Team + #LOC_BDArmory_WMWindow_selectionText = Weapon: <<1>> + #LOC_BDArmory_WMWindow_rippleText1 = Barrage: <<1>> RPM + #LOC_BDArmory_WMWindow_rippleText2 = Salvo + #LOC_BDArmory_WMWindow_rippleText3 = Ripple: <<1>> RPM + #LOC_BDArmory_WMWindow_rippleText4 = Ripple: OFF + #LOC_BDArmory_WMWindow_ListWeapons = Weapons + #LOC_BDArmory_WMWindow_GuardMenu = Guard Menu + #LOC_BDArmory_WMWindow_ModulesToggle = Modules + #LOC_BDArmory_WMWindow_NoneWeapon = None + #LOC_BDArmory_WMWindow_NoneWeapon = Guard Mode <<1>> + #LOC_BDArmory_WMWindow_FiringInterval = Firing Interval + #LOC_BDArmory_WMWindow_BurstLength = Burst Length + #LOC_BDArmory_WMWindow_FieldofView = Field of View + #LOC_BDArmory_WMWindow_VisualRange = Visual Range + #LOC_BDArmory_WMWindow_GunsRange = Guns Range + #LOC_BDArmory_WMWindow_MissilesTgt = Missiles/Tgt + #LOC_BDArmory_WMWindow_TargetType = Target Type: + #LOC_BDArmory_WMWindow_TargetType_Missiles = Missiles + #LOC_BDArmory_WMWindow_TargetType_All = All Targets + #LOC_BDArmory_WMWindow_RadarWarning = Radar Warning Receiver + #LOC_BDArmory_WMWindow_GPSCoordinator = GPS Coordinator + #LOC_BDArmory_WMWindow_WingCommand = Wing Command + #LOC_BDArmory_WMWindow_NoWeaponManager = No Weapon Manager found. + #LOC_BDArmory_WMWindow_GPSTarget = GPS Target + #LOC_BDArmory_WMWindow_NoTarget = No Target + #LOC_BDArmory_Settings_Title = BDArmory Settings + #LOC_BDArmory_Settings_Instakill = Instakill + #LOC_BDArmory_Settings_InfiniteAmmo = Infinite Ammo + #LOC_BDArmory_Settings_BulletHits = Bullet Hits + #LOC_BDArmory_Settings_EjectShells = Eject Shells + #LOC_BDArmory_Settings_AimAssist = Aim Assist + #LOC_BDArmory_Settings_DrawAimers = Draw Aimers + #LOC_BDArmory_Settings_DebugLines = Debug Lines + #LOC_BDArmory_Settings_DebugLabels = Debug Labels + #LOC_BDArmory_Settings_RemoteFiring = Remote Firing + #LOC_BDArmory_Settings_ClearanceCheck = Clearance Check + #LOC_BDArmory_Settings_AmmoGauges = Ammo Gauges + #LOC_BDArmory_Settings_ShellCollisions = Shell Collisions + #LOC_BDArmory_Settings_BulletHoleDecals = Bullet Hole Decals + #LOC_BDArmory_Settings_PerformanceLogging = Performance Logging + #LOC_BDArmory_Settings_ShowEditorSubcategories = Show Editor Subcategories + #LOC_BDArmory_Settings_AutocategorizeParts = Autocategorize Parts + #LOC_BDArmory_Settings_MaxBulletHoles = Max Bullet Holes + #LOC_BDArmory_Settings_PeaceMode = Peace Mode + #LOC_BDArmory_Settings_RWRWindowScale = RWR Window Scale + #LOC_BDArmory_Settings_RadarWindowScale = Radar Window Scale + #LOC_BDArmory_Settings_TargetWindowScale = Target Window Scale + #LOC_BDArmory_Settings_TriggerHold = Trigger Hold + #LOC_BDArmory_Settings_UIVolume = UI Volume + #LOC_BDArmory_Settings_WeaponVolume = Weapon Volume + #LOC_BDArmory_Settings_DogfightCompetition = Dogfight Competition + #LOC_BDArmory_Settings_CompetitionDistance = Competition Distance + #LOC_BDArmory_Settings_StartCompetition = Start Competition + #LOC_BDArmory_Settings_CompetitionStarting = Starting Competition... + #LOC_BDArmory_Settings_EditInputs = Edit Inputs + #LOC_BDArmory_Generic_SaveandClose = Save and Close + #LOC_BDArmory_InputSettings_Weapons = Weapons + #LOC_BDArmory_InputSettings_TargetingPod = Targeting Pod + #LOC_BDArmory_InputSettings_Radar = Radar + #LOC_BDArmory_InputSettings_VesselSwitcher = Vessel Switcher + #LOC_BDArmory_InputSettings_BackBtn = Back + #LOC_BDArmory_InputSettings_recordedInput = Press a key or button. + #LOC_BDArmory_InputSettings_SetKey = Set Key + #LOC_BDArmory_InputSettings_Clear = Clear + + #LOC_BDArmory_ProtoStageIconInfo_Reloading = Reloading + #LOC_BDArmory_ProtoStageIconInfo_Overheat = Overheat + #LOC_BDArmory_ProtoStageIconInfo_AmmoOut = Ammo Depleted + + #LOC_BDArmory_WingCommander_Title = WingCommander + #LOC_BDArmory_WingCommander_Guiname1 = Formation Spread + #LOC_BDArmory_WingCommander_Guiname2 = Formation Lag + #LOC_BDArmory_WingCommander_Guiname3 = ToggleGUI + #LOC_BDArmory_WingCommander_SelectAll = Select All + #LOC_BDArmory_WingCommander_CommandSelf = Command Self + #LOC_BDArmory_WingCommander_Follow = Follow + #LOC_BDArmory_WingCommander_FlyToPos = Fly To Pos + #LOC_BDArmory_WingCommander_AttackPos = Attack Pos + #LOC_BDArmory_WingCommander_ActionGroup = Action Group + #LOC_BDArmory_WingCommander_ActionGroups = Action Groups + #LOC_BDArmory_WingCommander_TakeOff = Take Off + #LOC_BDArmory_WingCommander_Release = Release + #LOC_BDArmory_WingCommander_FormationSettings = Formation Settings + #LOC_BDArmory_WingCommander_Spread = Spread + #LOC_BDArmory_WingCommander_Lag = Lag + #LOC_BDArmory_WingCommander_ScreenMessage = Select target coordinates.\nRight-click to cancel. + + #LOC_BDArmory_BDAVesselSwitcher_Title = BDA Vessel Switcher + + //GUI Names + #LOC_BDArmory_EjectVelocity = Eject Velocity + #LOC_BDArmory_TNTMass = TNT mass equivalent + #LOC_BDArmory_BlastRadius = Blast Radius + #LOC_BDArmory_WeaponName = Weapon Name\u0020 + #LOC_BDArmory_GuidanceType = Guidance Type\u0020 + #LOC_BDArmory_TargetingMode = Targeting Mode\u0020 + #LOC_BDArmory_ActiveRadarRange = Active Radar Range + #LOC_BDArmory_SteerLimiter = Steer Limiter + #LOC_BDArmory_StagesNumber = Stages Number + #LOC_BDArmory_StageToTriggerOnProximity = Stage to Trigger On Proximity + #LOC_BDArmory_SteerDamping = Steer Damping + #LOC_BDArmory_SteerFactor = Steer Factor + #LOC_BDArmory_RollCorrection = Roll Correction + #LOC_BDArmory_RollCorrection_enabledText = Roll enabled + #LOC_BDArmory_RollCorrection_disabledText = Roll disabled + #LOC_BDArmory_TimeBetweenStages = Time Between Stages + #LOC_BDArmory_MinSpeedGuidance = Min Speed before guidance + #LOC_BDArmory_ClearanceRadius = Clearance radius + #LOC_BDArmory_ClearanceLength = Clearance length + #LOC_BDArmory_showRFGUI = Show Weapon Name Editor + #LOC_BDArmory_showRFGUI_enabledText = Weapon Name GUI + #LOC_BDArmory_showRFGUI_disabledText = GUI + #LOC_BDArmory_DefaultAltitude = Default Alt. + #LOC_BDArmory_MinAltitude = Min Altitude + #LOC_BDArmory_SteerKi = Steer Ki + #LOC_BDArmory_MaxSpeed = Max Speed + #LOC_BDArmory_MaxDrift = Max drift + #LOC_BDArmory_TakeOffSpeed = TakeOff Speed + #LOC_BDArmory_MinSpeed = MinCombatSpeed + #LOC_BDArmory_IdleSpeed = Idle Speed + #LOC_BDArmory_maxAllowedGForce = Max G + #LOC_BDArmory_maxAllowedAoA = Max AoA + #LOC_BDArmory_Orbit = Orbit\u0020 + #LOC_BDArmory_Orbit_enabledText = Starboard (CW) + #LOC_BDArmory_Orbit_disabledText = Port (CCW) + #LOC_BDArmory_UnclampTuning = Unclamp tuning\u0020 + #LOC_BDArmory_UnclampTuning_enabledText = Unclamped + #LOC_BDArmory_UnclampTuning_disabledText = Clamped + #LOC_BDArmory_StandbyMode = Standby Mode + #LOC_BDArmory_On = On + #LOC_BDArmory_Off = Off + #LOC_BDArmory_VehicleType = Vehicle type + #LOC_BDArmory_MaxSlopeAngle = Max slope angle + #LOC_BDArmory_CruiseSpeed = Cruise speed + #LOC_BDArmory_TargetPitch = Moving pitch + #LOC_BDArmory_BankAngle = Bank angle + #LOC_BDArmory_BroadsideAttack = Attack vector + #LOC_BDArmory_BroadsideAttack_enabledText = Broadside + #LOC_BDArmory_BroadsideAttack_disabledText = Bow + #LOC_BDArmory_MinEngagementRange = Min engagement range + #LOC_BDArmory_MaxEngagementRange = Max engagement range + #LOC_BDArmory_ManeuverRCS = RCS active + #LOC_BDArmory_ManeuverRCS_enabledText = Maneuvers + #LOC_BDArmory_ManeuverRCS_disabledText = Combat + #LOC_BDArmory_MinObstacleMass = Min obstacle mass + #LOC_BDArmory_PreferredBroadsideDirection = Preferred broadside direction + #LOC_BDArmory_GoesUp = Goes up to + #LOC_BDArmory_GoesUp_enabledText = eleven + #LOC_BDArmory_GoesUp_disabledText = ten + #LOC_BDArmory_Rails = Rails + #LOC_BDArmory_DeployAltitude = Deploy Altitude + #LOC_BDArmory_EngageRangeMin = Engage Range Min + #LOC_BDArmory_EngageRangeMax = Engage Range Max + #LOC_BDArmory_EngageAir = Engage Air + #LOC_BDArmory_EngageMissile = Engage Missile + #LOC_BDArmory_EngageSurface = Engage Surface + #LOC_BDArmory_EngageSLW = Engage SLW + #LOC_BDArmory_DisableEngageOptions = Disable Engage Options + #LOC_BDArmory_EnableEngageOptions = Enable Engage Options + #LOC_BDArmory_MaxStaticLaunchRange = Max Static Launch Range + #LOC_BDArmory_MinStaticLaunchRange = Min Static Launch Range + #LOC_BDArmory_MaxOffBoresight = Max Off Boresight + #LOC_BDArmory_DetonationDistanceOverride = Detonation distance override + #LOC_BDArmory_DropTime = Drop Time + #LOC_BDArmory_InCargoBay = In Cargo Bay:\u0020 + #LOC_BDArmory_DetonationTime = Detonation Time + #LOC_BDArmory_BallisticOvershootFactor = Ballistic Overshoot factor + #LOC_BDArmory_BallisticAnglePath = Ballistic Angle path + #LOC_BDArmory_CruiseAltitude = Cruise Altitude + #LOC_BDArmory_CruisePredictionTime = Cruise prediction time + #LOC_BDArmory_GPSTarget = GPS Target + #LOC_BDArmory_FiringInterval = Firing Interval + #LOC_BDArmory_FiringBurstLength = Firing Burst Length + #LOC_BDArmory_FieldOfView = Field of View + #LOC_BDArmory_VisualRange = Visual Range + #LOC_BDArmory_GunsRange = Guns Range + #LOC_BDArmory_MissilesORTarget = Missiles/Target + #LOC_BDArmory_GaurdMode = Gaurd Mode:\u0020 + #LOC_BDArmory_Team = Team + #LOC_BDArmory_Weapon = Weapon + #LOC_BDArmory_Direction = Direction:\u0020 + #LOC_BDArmory_Direction_disabledText = Lateral + #LOC_BDArmory_Direction_enabledText = Forward + #LOC_BDArmory_DecoupleSpeed = Decouple Speed + #LOC_BDArmory_MaxAltitude = Max Altitude + #LOC_BDArmory_TerminalGuidance = Terminal Guidance:\u0020 + #LOC_BDArmory_false = False + #LOC_BDArmory_true = True + #LOC_BDArmory_TurretEnabled = Turret Enabled + #LOC_BDArmory_AutoReturn = Auto-Return + #LOC_BDArmory_AddedCost = Added cost + #LOC_BDArmory_DryMass = Dry mass + #LOC_BDArmory_Enabled = Enabled + #LOC_BDArmory_Enable = Enable + #LOC_BDArmory_EMPBlastRadius = EMP Blast Radius + #LOC_BDArmory_OrdinanceAvailable = Ordinance Available + #LOC_BDArmory_MissileAssign = Missile Assign + #LOC_BDArmory_CurrentLocks = Current Locks + #LOC_BDArmory_MaxPitch = Max Pitch + #LOC_BDArmory_MinPitch = Min Pitch + #LOC_BDArmory_YawRange = Yaw Range + #LOC_BDArmory_FireLimits = Fire Limits + #LOC_BDArmory_FireLimits_disabledText = None + #LOC_BDArmory_FireLimits_enabledText = In range + #LOC_BDArmory_DefaultDetonationRange = Fuzed Detonation Range\u0020 + #LOC_BDArmory_ProximityFuzeRadius = Proximity Fuze Radius + #LOC_BDArmory_MaxDetonationRange = Max Detonation Range + #LOC_BDArmory_Barrage = Barrage + #LOC_BDArmory_ToggleBarrage = Toggle Barrage + #LOC_BDArmory_Status = Status + #LOC_BDArmory_Toggle = Toggle + #LOC_BDArmory_ShowGroupEditor = Show Group Editor + #LOC_BDArmory_ShowGroupEditor_enabledText = close Group GUI + #LOC_BDArmory_ShowGroupEditor_disabledText = open Group GUI + #LOC_BDArmory_DeactivationDepth = Deactivation Depth + #LOC_BDArmory_Hitpoints = Hitpoints + #LOC_BDArmory_ArmorThickness = Armor Thickness + #LOC_BDArmory_FireCountermeasure = Fire Countermeasure + #LOC_BDArmory_IncreaseHeight = Height ++ + #LOC_BDArmory_DecreaseHeight = Height -- + #LOC_BDArmory_IncreaseLength = Length ++ + #LOC_BDArmory_DecreaseLength = Length -- + #LOC_BDArmory_Detonate = Detonate + #LOC_BDArmory_TogglePilot = Toggle Pilot + #LOC_BDArmory_DeactivatePilot = Deactivate Pilot + #LOC_BDArmory_ActivatePilot = Activate Pilot + #LOC_BDArmory_FireMissile = Fire Missile + #LOC_BDArmory_GuidanceMode = Guidance Mode + #LOC_BDArmory_Jettison = Jettison + #LOC_BDArmory_ToggleTurret = Toggle Turret + #LOC_BDArmory_HideUI = Hide Weapon Name UI + #LOC_BDArmory_ShowUI = Set Weapon Name UI + #LOC_BDArmory_RailsPlus = Rails++ + #LOC_BDArmory_RailsMinus = Rails-- + #LOC_BDArmory_ChangetoLowAltitudeRange = Change to Low Altitude Range + #LOC_BDArmory_SelectTeam = Select Team + #LOC_BDArmory_OpenGUI = Open GUI + #LOC_BDArmory_ReturnTurret = Return Turret + #LOC_BDArmory_ToggleAnimation = Toggle Animation + #LOC_BDArmory_NextTankSetup = Next tank setup + #LOC_BDArmory_PreviousTankSetup = Previous tank setup + #LOC_BDArmory_Resupply = Resupply + #LOC_BDArmory_ToggleRadar = Toggle Radar + #LOC_BDArmory_NextTexture = Next Texture + #LOC_BDArmory_HideWeaponGroupUI = Hide Weapon Group UI + #LOC_BDArmory_SetWeaponGroupUI = Set Weapon Group UI + #LOC_BDArmory_Fire = Fire + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Localization/UI/zh-cn.cfg b/BDArmory/Distribution/GameData/BDArmory/Localization/UI/zh-cn.cfg new file mode 100644 index 000000000..b0845c0ad --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Localization/UI/zh-cn.cfg @@ -0,0 +1,266 @@ +Localization +{ + zh-cn + { + #LOC_BDArmory_Generic_Cancel = 取消 + #LOC_BDArmory_Generic_New = 新建 + #LOC_BDArmory_Generic_On = 开 + #LOC_BDArmory_Generic_Off = 关 + #LOC_BDArmory_VesselStatus_Landed = (着陆) + #LOC_BDArmory_VesselStatus_Splashed = (溅落) + + #LOC_BDArmory_WMWindow_title = BDA武器管理器 + #LOC_BDArmory_WMWindow_GuardModebtn = 警戒模式 + #LOC_BDArmory_WMWindow_ArmedText = 扳机 + #LOC_BDArmory_WMWindow_ArmedText_ARMED = 已上膛. + #LOC_BDArmory_WMWindow_ArmedText_DisArmed = 已锁定. + #LOC_BDArmory_WMWindow_TeamText = 小队 + #LOC_BDArmory_WMWindow_selectionText = 武器: <<1>> + #LOC_BDArmory_WMWindow_rippleText1 = 齐射: <<1>> RPM + #LOC_BDArmory_WMWindow_rippleText2 = 齐射 + #LOC_BDArmory_WMWindow_rippleText3 = Ripple: <<1>> RPM + #LOC_BDArmory_WMWindow_rippleText4 = Ripple: OFF + #LOC_BDArmory_WMWindow_ListWeapons = 所有武器 + #LOC_BDArmory_WMWindow_GuardMenu = 警戒菜单 + #LOC_BDArmory_WMWindow_ModulesToggle = 模块 + #LOC_BDArmory_WMWindow_NoneWeapon = 无 + #LOC_BDArmory_WMWindow_NoneWeapon = 警戒模式 <<1>> + #LOC_BDArmory_WMWindow_FiringInterval = 射击间隔 + #LOC_BDArmory_WMWindow_BurstLength = Burst Length + #LOC_BDArmory_WMWindow_FieldofView = 视场范围 + #LOC_BDArmory_WMWindow_VisualRange = 视距 + #LOC_BDArmory_WMWindow_GunsRange = 枪炮射程 + #LOC_BDArmory_WMWindow_MissilesTgt = 导弹/目标 + #LOC_BDArmory_WMWindow_TargetType = 制导类型: + #LOC_BDArmory_WMWindow_TargetType_Missiles = 导弹 + #LOC_BDArmory_WMWindow_TargetType_All = 所有目标 + #LOC_BDArmory_WMWindow_RadarWarning = 雷达告警接收机 + #LOC_BDArmory_WMWindow_GPSCoordinator = GPS坐标面板 + #LOC_BDArmory_WMWindow_WingCommand = 僚机控制 + #LOC_BDArmory_WMWindow_NoWeaponManager = 没有找到武器管理器. + #LOC_BDArmory_WMWindow_GPSTarget = GPS目标 + #LOC_BDArmory_WMWindow_NoTarget = 无目标 + #LOC_BDArmory_Settings_Title = BDArmory设置 + #LOC_BDArmory_Settings_Instakill = 一击必杀 + #LOC_BDArmory_Settings_InfiniteAmmo = 无限子弹 + #LOC_BDArmory_Settings_BulletHits = 子弹击中 + #LOC_BDArmory_Settings_EjectShells = 跳弹 + #LOC_BDArmory_Settings_AimAssist = 瞄准辅助 + #LOC_BDArmory_Settings_DrawAimers = Draw Aimers + #LOC_BDArmory_Settings_DebugLines = Debug线条 + #LOC_BDArmory_Settings_DebugLabels = Debug标签 + #LOC_BDArmory_Settings_RemoteFiring = 远程射击 + #LOC_BDArmory_Settings_ClearanceCheck = 安全间距检查 + #LOC_BDArmory_Settings_AmmoGauges = 弹药列表 + #LOC_BDArmory_Settings_ShellCollisions = 弹药碰撞 + #LOC_BDArmory_Settings_BulletHoleDecals = 弹孔显示 + #LOC_BDArmory_Settings_PerformanceLogging = 性能日志 + #LOC_BDArmory_Settings_ShowEditorSubcategories = 航天大楼里显示BDA分类 + #LOC_BDArmory_Settings_AutocategorizeParts = 自动分类部件 + #LOC_BDArmory_Settings_MaxBulletHoles = 最大弹孔数量 + #LOC_BDArmory_Settings_PeaceMode = 和平模式 + #LOC_BDArmory_Settings_RWRWindowScale = RWR窗口比例 + #LOC_BDArmory_Settings_RadarWindowScale = 雷达窗口比例 + #LOC_BDArmory_Settings_TargetWindowScale = 目标窗口比例 + #LOC_BDArmory_Settings_TriggerHold = 长按扳机 + #LOC_BDArmory_Settings_UIVolume = 用户界面大小 + #LOC_BDArmory_Settings_WeaponVolume = 武器大小 + #LOC_BDArmory_Settings_DogfightCompetition = 缠斗比赛 + #LOC_BDArmory_Settings_CompetitionDistance = 比赛距离 + #LOC_BDArmory_Settings_StartCompetition = 开始比赛 + #LOC_BDArmory_Settings_CompetitionStarting = 开始比赛中... + #LOC_BDArmory_Settings_EditInputs = 编辑键位 + #LOC_BDArmory_Generic_SaveandClose = 保存退出 + #LOC_BDArmory_InputSettings_Weapons = 武器 + #LOC_BDArmory_InputSettings_TargetingPod = 瞄准吊舱 + #LOC_BDArmory_InputSettings_Radar = 雷达 + #LOC_BDArmory_InputSettings_VesselSwitcher = 载具切换 + #LOC_BDArmory_InputSettings_BackBtn = 返回 + #LOC_BDArmory_InputSettings_recordedInput = 按一个键或按钮. + #LOC_BDArmory_InputSettings_SetKey = 设置按键 + #LOC_BDArmory_InputSettings_Clear = 清除 + + #LOC_BDArmory_ProtoStageIconInfo_Reloading = 装弹中 + #LOC_BDArmory_ProtoStageIconInfo_Overheat = 过热 + #LOC_BDArmory_ProtoStageIconInfo_AmmoOut = 弹药耗尽 + + #LOC_BDArmory_WingCommander_Title = 僚机控制 + #LOC_BDArmory_WingCommander_Guiname1 = 编队散开 + #LOC_BDArmory_WingCommander_Guiname2 = Formation Lag + #LOC_BDArmory_WingCommander_Guiname3 = 切换界面 + #LOC_BDArmory_WingCommander_SelectAll = 选择全部 + #LOC_BDArmory_WingCommander_CommandSelf = Command Self + #LOC_BDArmory_WingCommander_Follow = 跟随 + #LOC_BDArmory_WingCommander_FlyToPos = Fly To Pos + #LOC_BDArmory_WingCommander_AttackPos = Attack Pos + #LOC_BDArmory_WingCommander_ActionGroup = 动作组 + #LOC_BDArmory_WingCommander_ActionGroups = 动作组 + #LOC_BDArmory_WingCommander_TakeOff = 起飞 + #LOC_BDArmory_WingCommander_Release = 释放 + #LOC_BDArmory_WingCommander_FormationSettings = 编队设置 + #LOC_BDArmory_WingCommander_Spread = 分散 + #LOC_BDArmory_WingCommander_Lag = Lag + #LOC_BDArmory_WingCommander_ScreenMessage = 选择目标坐标.\n右键取消. + + #LOC_BDArmory_BDAVesselSwitcher_Title = BDA 载具切换 + + //GUI Names + #LOC_BDArmory_EjectVelocity = 喷射速度 + #LOC_BDArmory_TNTMass = TNT质量等效 + #LOC_BDArmory_BlastRadius = 爆炸半径 + #LOC_BDArmory_WeaponName = 武器名\u0020 + #LOC_BDArmory_GuidanceType = 制导类型\u0020 + #LOC_BDArmory_TargetingMode = 目标模式\u0020 + #LOC_BDArmory_ActiveRadarRange = 主动雷达范围 + #LOC_BDArmory_SteerLimiter = 制导限制 + #LOC_BDArmory_StagesNumber = 分级编号 + #LOC_BDArmory_StageToTriggerOnProximity = 在接近时分级引爆 + #LOC_BDArmory_SteerDamping = 制导阻尼 + #LOC_BDArmory_SteerFactor = Steer Factor + #LOC_BDArmory_RollCorrection = 翻滚修正 + #LOC_BDArmory_RollCorrection_enabledText = Roll enabled + #LOC_BDArmory_RollCorrection_disabledText = Roll disabled + #LOC_BDArmory_TimeBetweenStages = 分级间隔 + #LOC_BDArmory_MinSpeedGuidance = 制导前最低速度 + #LOC_BDArmory_ClearanceRadius = 安全间距半径 + #LOC_BDArmory_ClearanceLength = 安全间距长度 + #LOC_BDArmory_showRFGUI = 显示武器名称编辑器 + #LOC_BDArmory_showRFGUI_enabledText = 武器名称界面 + #LOC_BDArmory_showRFGUI_disabledText = 界面 + #LOC_BDArmory_DefaultAltitude = 默认高度 + #LOC_BDArmory_MinAltitude = 最低高度 + #LOC_BDArmory_SteerKi = Steer Ki + #LOC_BDArmory_MaxSpeed = 最大速度 + #LOC_BDArmory_MaxDrift = Max drift + #LOC_BDArmory_TakeOffSpeed = 起飞速度 + #LOC_BDArmory_MinSpeed = 最低战斗速度 + #LOC_BDArmory_IdleSpeed = 怠速 + #LOC_BDArmory_maxAllowedGForce = 最大G力 + #LOC_BDArmory_maxAllowedAoA = 最大攻角 + #LOC_BDArmory_Orbit = 绕\u0020 + #LOC_BDArmory_Orbit_enabledText = 右舷 (顺时针) + #LOC_BDArmory_Orbit_disabledText = Port (逆时针) + #LOC_BDArmory_UnclampTuning = Unclamp tuning\u0020 + #LOC_BDArmory_UnclampTuning_enabledText = 分离 + #LOC_BDArmory_UnclampTuning_disabledText = 夹紧 + #LOC_BDArmory_StandbyMode = 待机模式 + #LOC_BDArmory_On = 开 + #LOC_BDArmory_Off = 关 + #LOC_BDArmory_VehicleType = 车辆类型 + #LOC_BDArmory_MaxSlopeAngle = 最大坡度角 + #LOC_BDArmory_CruiseSpeed = 巡航速度 + #LOC_BDArmory_TargetPitch = 移动俯仰 + #LOC_BDArmory_BankAngle = 倾斜角 + #LOC_BDArmory_BroadsideAttack = 攻击方向 + #LOC_BDArmory_BroadsideAttack_enabledText = 侧面 + #LOC_BDArmory_BroadsideAttack_disabledText = 前 + #LOC_BDArmory_MinEngagementRange = 最小遭遇范围 + #LOC_BDArmory_MaxEngagementRange = 最大遭遇范围 + #LOC_BDArmory_ManeuverRCS = RCS启动 + #LOC_BDArmory_ManeuverRCS_enabledText = 机动 + #LOC_BDArmory_ManeuverRCS_disabledText = 战斗 + #LOC_BDArmory_MinObstacleMass = 最小障碍物质量 + #LOC_BDArmory_PreferredBroadsideDirection = 首选侧向方向 + #LOC_BDArmory_GoesUp = 上升到 + #LOC_BDArmory_GoesUp_enabledText = 11 + #LOC_BDArmory_GoesUp_disabledText = 10 + #LOC_BDArmory_Rails = Rails + #LOC_BDArmory_DeployAltitude = 分离高度 + #LOC_BDArmory_EngageRangeMin = 遭遇范围最小值 + #LOC_BDArmory_EngageRangeMax = 遭遇范围最大值 + #LOC_BDArmory_EngageAir = Engage空气 + #LOC_BDArmory_EngageMissile = Engage导弹 + #LOC_BDArmory_EngageSurface = Engage地面 + #LOC_BDArmory_EngageSLW = Engage SLW + #LOC_BDArmory_DisableEngageOptions = Disable Engage Options + #LOC_BDArmory_EnableEngageOptions = Enable Engage Options + #LOC_BDArmory_MaxStaticLaunchRange = 最大静态发射距离 + #LOC_BDArmory_MinStaticLaunchRange = 最小静态发射距离 + #LOC_BDArmory_MaxOffBoresight = Max Off Boresight + #LOC_BDArmory_DetonationDistanceOverride = 爆轰距离覆盖 + #LOC_BDArmory_DropTime = 下降时间 + #LOC_BDArmory_InCargoBay = 在弹仓:\u0020 + #LOC_BDArmory_DetonationTime = 爆炸时间 + #LOC_BDArmory_BallisticOvershootFactor = Ballistic Overshoot factor + #LOC_BDArmory_BallisticAnglePath = Ballistic Angle path + #LOC_BDArmory_CruiseAltitude = 巡航高度 + #LOC_BDArmory_CruisePredictionTime = 巡航预测时间 + #LOC_BDArmory_GPSTarget = GPS目标 + #LOC_BDArmory_FiringInterval = 射击间隔 + #LOC_BDArmory_FiringBurstLength = Firing Burst Length + #LOC_BDArmory_FieldOfView = 视场范围 + #LOC_BDArmory_VisualRange = 可视距离 + #LOC_BDArmory_GunsRange = 武器范围 + #LOC_BDArmory_MissilesORTarget = 导弹/目标 + #LOC_BDArmory_GaurdMode = 警戒模式:\u0020 + #LOC_BDArmory_Team = 小队 + #LOC_BDArmory_Weapon = 武器 + #LOC_BDArmory_Direction = 方向:\u0020 + #LOC_BDArmory_Direction_disabledText = 横向 + #LOC_BDArmory_Direction_enabledText = 向前 + #LOC_BDArmory_DecoupleSpeed = 分离速度 + #LOC_BDArmory_MaxAltitude = 最大高度 + #LOC_BDArmory_TerminalGuidance = 终端制导:\u0020 + #LOC_BDArmory_false = 否 + #LOC_BDArmory_true = 是 + #LOC_BDArmory_TurretEnabled = 炮塔开启 + #LOC_BDArmory_AutoReturn = 自动返回 + #LOC_BDArmory_AddedCost = 增加成本 + #LOC_BDArmory_DryMass = 干质量 + #LOC_BDArmory_Enabled = 开启 + #LOC_BDArmory_Enable = Enable + #LOC_BDArmory_EMPBlastRadius = EMP Blast Radius + #LOC_BDArmory_OrdinanceAvailable = Ordinance Available + #LOC_BDArmory_MissileAssign = 导弹分配 + #LOC_BDArmory_CurrentLocks = 当前锁定 + #LOC_BDArmory_MaxPitch = Max Pitch + #LOC_BDArmory_MinPitch = Min Pitch + #LOC_BDArmory_YawRange = Yaw Range + #LOC_BDArmory_FireLimits = 开火限制 + #LOC_BDArmory_FireLimits_disabledText = 无 + #LOC_BDArmory_FireLimits_enabledText = 在范围内 + #LOC_BDArmory_DefaultDetonationRange = 引信启动爆炸距离\u0020 + #LOC_BDArmory_ProximityFuzeRadius = Proximity Fuze Radius + #LOC_BDArmory_MaxDetonationRange = 最大爆炸范围 + #LOC_BDArmory_Barrage = 弹幕射击 + #LOC_BDArmory_ToggleBarrage = 开关弹幕射击 + #LOC_BDArmory_Status = 状态 + #LOC_BDArmory_Toggle = 切换 + #LOC_BDArmory_ShowGroupEditor = Show Group Editor + #LOC_BDArmory_ShowGroupEditor_enabledText = close Group GUI + #LOC_BDArmory_ShowGroupEditor_disabledText = open Group GUI + #LOC_BDArmory_DeactivationDepth = Deactivation Depth + #LOC_BDArmory_Hitpoints = 生命值 + #LOC_BDArmory_ArmorThickness = 装甲厚度 + #LOC_BDArmory_FireCountermeasure = 开火反制 + #LOC_BDArmory_IncreaseHeight = 高度 ++ + #LOC_BDArmory_DecreaseHeight = 高度 -- + #LOC_BDArmory_IncreaseLength = 长度 ++ + #LOC_BDArmory_DecreaseLength = 长度 -- + #LOC_BDArmory_Detonate = 引爆 + #LOC_BDArmory_TogglePilot = 开关自动驾驶 + #LOC_BDArmory_DeactivatePilot = 手动驾驶 + #LOC_BDArmory_ActivatePilot = 自动驾驶 + #LOC_BDArmory_FireMissile = 发射导弹 + #LOC_BDArmory_GuidanceMode = 制导模式 + #LOC_BDArmory_Jettison = 投弃 + #LOC_BDArmory_ToggleTurret = 切换炮塔 + #LOC_BDArmory_HideUI = 隐藏武器名界面 + #LOC_BDArmory_ShowUI = 设置武器名界面 + #LOC_BDArmory_RailsPlus = Rails++ + #LOC_BDArmory_RailsMinus = Rails-- + #LOC_BDArmory_ChangetoLowAltitudeRange = 转向低空飞行 + #LOC_BDArmory_SelectTeam = 选择队伍 + #LOC_BDArmory_OpenGUI = 打开界面 + #LOC_BDArmory_ReturnTurret = 返回炮塔 + #LOC_BDArmory_ToggleAnimation = 开关动画 + #LOC_BDArmory_NextTankSetup = 下个配置箱 + #LOC_BDArmory_PreviousTankSetup = 上个配置箱 + #LOC_BDArmory_Resupply = Resupply + #LOC_BDArmory_ToggleRadar = 开关雷达 + #LOC_BDArmory_NextTexture = 下一贴图 + #LOC_BDArmory_HideWeaponGroupUI = 隐藏武器组界面 + #LOC_BDArmory_SetWeaponGroupUI = 设置武器组界面 + #LOC_BDArmory_Fire = 开火 + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Localization/localization-en-us.cfg b/BDArmory/Distribution/GameData/BDArmory/Localization/localization-en-us.cfg new file mode 100644 index 000000000..676a3f49e --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Localization/localization-en-us.cfg @@ -0,0 +1,336 @@ +Localization +{ + en-us + { + #loc_BDArmory_modname = BD Armory + + #loc_BDArmory_agent_title = Bahamuto Dynamics + #loc_BDArmory_agent_description = Leading manufacturer of military arms and munitions. The company is also occasionally contracted by the space program for advanced or unique engineering solutions. + #loc_BDArmory_part_manufacturer = Bahamuto Dynamics + + //Vulcan Turret + #loc_BDArmory_part_bahaGatlingGun_title = Vulcan Turret + //A 6 barrel 20x102mm rotary cannon. + #loc_BDArmory_part_bahaGatlingGun_description = A 6 barrel 20x102mm rotary cannon. + + //.50cal Turret + #loc_BDArmory_part_bahaTurret_title = .50cal Turret + //A dual barrel .50 cal machine gun. + #loc_BDArmory_part_bahaTurret_description = A dual barrel .50 cal machine gun. + + //USAF Airborne Laser + #loc_BDArmory_part_bahaABL_title = USAF Airborne Laser + //A high powered laser for setting things on fire. Uses 350 electric charge per second. + #loc_BDArmory_part_bahaABL_description = A high powered laser for setting things on fire. Uses 350 electric charge per second. + + //Adjustable Missile Rail + #loc_BDArmory_part_bahaAdjustableRail_title = Adjustable Missile Rail + //A rail for mounting missiles. + #loc_BDArmory_part_bahaAdjustableRail_description = A rail for mounting missiles. + + //AGM-86C Cruise Missile + #loc_BDArmory_part_bahaAgm86B_title = AGM-86C Cruise Missile + //Long distance, sub-sonic, air-launched, GPS-guided cruise missile. This missile has no booster, so it must be launched while airborne at cruising speed. + #loc_BDArmory_part_bahaAgm86B_description = Long distance, sub-sonic, air-launched, GPS-guided cruise missile. This missile has no booster, so it must be launched while airborne at cruising speed. + + //AIM-120 AMRAAM Missile + #loc_BDArmory_part_bahaAim120_title = AIM-120 AMRAAM Missile + //Medium range radar guided homing missile. + #loc_BDArmory_part_bahaAim120_description = Medium range radar guided homing missile. + + //AI Pilot Flight Computer + #loc_BDArmory_part_bdPilotAI_title = AI Pilot Flight Computer + //Flies your plane on combat air patrol missions without using your hands. Tune the values based on your plane's unique flight characteristics. Please activate engines manually. Works in conjunction with a weapon manager in guard mode (attach and configure separately). (EXPERIMENTAL) + #loc_BDArmory_part_bdPilotAI_description = Flies your plane on combat air patrol missions without using your hands. Tune the values based on your plane's unique flight characteristics. Please activate engines manually. Works in conjunction with a weapon manager in guard mode (attach and configure separately). (EXPERIMENTAL) + + //20mm Ammunition Box + #loc_BDArmory_part_baha20mmAmmo_title = 20mm Ammunition Box + //Ammo box containing 650 20x102mm rounds. + #loc_BDArmory_part_baha20mmAmmo_description = Ammo box containing 650 20x102mm rounds. + + //30mm Ammunition Box + #loc_BDArmory_part_baha30mmAmmo_title = 30mm Ammunition Box + //Ammo box containing 600 30x173mm rounds. + #loc_BDArmory_part_baha30mmAmmo_description = Ammo box containing 600 30x173mm rounds. + + //50cal Ammunition Box + #loc_BDArmory_part_baha50CalAmmo_title = 50cal Ammunition Box + //Ammo box containing 1200 .50 cal rounds. + #loc_BDArmory_part_baha50CalAmmo_description = Ammo box containing 1200 .50 cal rounds. + + //Universal Ammo Box (Legacy) + #loc_BDArmory_part_UniversalAmmoBoxBDA_title = Universal Ammo Box (Legacy) + //(Obsolete - DO NOT USE - Requires Fire Spitter) Scalable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) NOTE: this part still requires Fire Spitter, and is here for backwards compatability. Use the new UniversalAmmo part going forward. + #loc_BDArmory_part_UniversalAmmoBoxBDA_description = (Obsolete - DO NOT USE - Requires Fire Spitter) Scalable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) NOTE: this part still requires Fire Spitter, and is here for backwards compatability. Use the new UniversalAmmo part going forward. + + //Universal Ammo Box + #loc_BDArmory_part_BDAcUniversalAmmoBox_title = Universal Ammo Box + //Scaleable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) + #loc_BDArmory_part_BDAcUniversalAmmoBox_description = Scaleable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) + + //Cannon Ammunition Box + #loc_BDArmory_part_bahaCannonShellBox_title = Cannon Ammunition Box + //Ammo box containing 10 cannon shells. + #loc_BDArmory_part_bahaCannonShellBox_description = Ammo box containing 10 cannon shells. + + //BD 1x1 slope Armor + #loc_BDArmory_part_BD1x1slopeArmor_title = BD 1x1 slope Armor + //A sturdy 1x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD1x1slopeArmor_description = A sturdy 1x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + + //BD 2x1 slope Armor + #loc_BDArmory_part_BD2x1slopeArmor_title = BD 2x1 slope Armor + //A sturdy 2x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD2x1slopeArmor_description = A sturdy 2x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + + //BD 1x1 panel Armor + #loc_BDArmory_part_BD1x1panelArmor_title = BD 1x1 panel Armor + //A sturdy 1x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD1x1panelArmor_description = A sturdy 1x1 Armor plate, perfect for constructing all sorts of things. PS does not float + + //BD 2x1 panel Armor + #loc_BDArmory_part_BD2x1panelArmor_title = BD 2x1 panel Armor + //A sturdy 2x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD2x1panelArmor_description = A sturdy 2x1 Armor plate, perfect for constructing all sorts of things. PS does not float + + //BD 3x1 panel Armor + #loc_BDArmory_part_BD3x1panelArmor_title = BD 3x1 panel Armor + //A sturdy 3x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD3x1panelArmor_description = A sturdy 3x1 Armor plate, perfect for constructing all sorts of things. PS does not float + + //BD 4x1 panel Armor + #loc_BDArmory_part_BD4x1panelArmor_title = BD 4x1 panel Armor + //A sturdy 4x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD4x1panelArmor_description = A sturdy 4x1 Armor plate, perfect for constructing all sorts of things. PS does not float + + //AWACS Detection Radar + #loc_BDArmory_part_awacsRadar_title = AWACS Detection Radar + //A large radar capable of detecting objects from a long distance. This radar does NOT have the capability of tracking or locking targets. + #loc_BDArmory_part_awacsRadar_description = A large radar capable of detecting objects from a long distance. This radar does NOT have the capability of tracking or locking targets. + + //Modular Missile Guidance (EXPERIMENTAL) + #loc_BDArmory_part_bdammGuidanceModule_title = Modular Missile Guidance (EXPERIMENTAL) + //A missile guidance computer. Manually tune steering settings to craft's unique flight characteristics. Select a guidance mode. Select a target then enable guidance. Activate engines and stages manually. (EXPERIMENTAL) + #loc_BDArmory_part_bdammGuidanceModule_description = A missile guidance computer. Manually tune steering settings to craft's unique flight characteristics. Select a guidance mode. Select a target then enable guidance. Activate engines and stages manually. (EXPERIMENTAL) + + //Browning .50cal AN/M2 + #loc_BDArmory_part_bahaBrowningAnm2_title = Browning .50cal AN/M3 + //An old fixed .50 cal machine gun 50cal ammo + #loc_BDArmory_part_bahaBrowningAnm2_description = An old fixed .50 cal machine gun 50cal ammo + + //CBU-87 Cluster Bomb + #loc_BDArmory_part_bahaClusterBomb_title = CBU-87 Cluster Bomb + //This bomb splits open and deploys many small bomblets at a certain altitude. + #loc_BDArmory_part_bahaClusterBomb_description = This bomb splits open and deploys many small bomblets at a certain altitude. + + //Chaff Dispenser + #loc_BDArmory_part_bahaChaffPod_title = Chaff Dispenser + //Drops chaff for confusing or breaking radar locks. + #loc_BDArmory_part_bahaChaffPod_description = Drops chaff for confusing or breaking radar locks. + + //Flare Dispenser + #loc_BDArmory_part_bahaCmPod_title = Flare Dispenser + //Drops flares for confusing heat-seeking missiles. + #loc_BDArmory_part_bahaCmPod_description = Drops flares for confusing heat-seeking missiles. + + //AN/ALQ-131 ECM Jammer + #loc_BDArmory_part_bahaECMJammer_title = AN/ALQ-131 ECM Jammer + //This electronic device makes it harder for radars to lock onto your vehicle, and increases your chances of breaking the lock. + #loc_BDArmory_part_bahaECMJammer_description = This electronic device makes it harder for radars to lock onto your vehicle, and increases your chances of breaking the lock. + + //GAU-8 30x173mm Cannon + #loc_BDArmory_part_bahaGau-8_title = GAU-8 30x173mm Cannon + //A 7 barrel 30mm rotary cannon. + #loc_BDArmory_part_bahaGau-8_description = A 7 barrel 30mm rotary cannon. + + //Goalkeeper CIWS + #loc_BDArmory_part_bahaGoalKeeper_title = Goalkeeper CIWS + #loc_BDArmory_part_bahaGoalKeeper_description = A 7 barrel 30mm rotary cannon with full swivel range. The 30mm high explosive rounds self detonate at the set distance, but this weapon does not feature automatic fuse timing. It has its own detection & tracking radar, though that is only effective at close range and does not replace a proper volumen serach radar. + + //GoalkeeperMk1 CIWS + #loc_BDArmory_part_GoalKeeperBDAcMk1_title = GoalkeeperMk1 CIWS + #loc_BDArmory_part_GoalKeeperBDAcMk1_description = A 7 barrel 30mm rotary cannon with full swivel range.This MK 1 version was found under a tarpaulin in a muddy field, Perfect for cash strapped militias and shifty governments (cheapskate version) Without Radar or detection equipment this turret requires the target information to be fed from an alternative source.(somebody pointing and shouting 'shoot that' has been found to be only marginally effective due to the excessive noise produced when the weapon fires) The 30mm high explosive rounds self detonate when they lose interest in flying, but this weapon does not feature automatic fuse timing. + + //Goalkeeper MK2 CIWS + #loc_BDArmory_part_BDAcGKmk2_title = Goalkeeper MK2 CIWS + #loc_BDArmory_part_BDAcGKmk2_description = A 7 barrel 30mm rotary cannon with full swivel range. This MK 2 version was found covered in overspray and paint cans around the back of the hangar at the old KSC, developed from the MK1 to reduce the incidence of hearing loss amongst early target pointers. This MK2 has some slight advantages over the MK1, equipped with Infra red targeting and Radar data reciever The 30x173mm high explosive rounds are only a slight improvement over the MK1 ammunition in that they at least take slightly longer to lose interest in flying and so have a good chance of reaching the target, but this weapon was never equipped to feature automatic fuse timing. + + //TWS Locking Radar + #loc_BDArmory_part_scanLockRadar1_title = TWS Locking Radar + #loc_BDArmory_part_scanLockRadar1_description = This unit has a medium range detection radar and a built-in target tracking radar. This radar is capable of locking targets, and will continue to scan while tracking the locked target (TWS - Track While Scan). It is optimized for air search&track, and has difficulties detecting and tracking surface targets. + + //Large Detection Radar + #loc_BDArmory_part_scanLargeRadar_title = Large Detection Radar + #loc_BDArmory_part_scanLargeRadar_description = A large radar capable of detecting objects from a long distance. This radar does NOT have the capability of tracking or locking targets. It is optimized for air search, and has difficulties detecting surface targets. + + //Hydra-70 Rocket Pod + #loc_BDArmory_part_bahaH70Launcher_title = Hydra-70 Rocket Pod + //Holds and fires 19 unguided Hydra-70 rockets. + #loc_BDArmory_part_bahaH70Launcher_description = Holds and fires 19 unguided Hydra-70 rockets. + + //Hydra-70 Rocket Turret + #loc_BDArmory_part_bahaH70Turret_title = Hydra-70 Rocket Turret + //Turret pod that holds and fires 32 unguided Hydra-70 rockets. + #loc_BDArmory_part_bahaH70Turret_description = Turret pod that holds and fires 32 unguided Hydra-70 rockets. + + //AGM-88 HARM Missile + #loc_BDArmory_part_bahaHarm_title = AGM-88 HARM Missile + //High-speed anti-radiation missile. This missile will home in on radar sources detected by the Radar Warning Receiver. + #loc_BDArmory_part_bahaHarm_description = High-speed anti-radiation missile. This missile will home in on radar sources detected by the Radar Warning Receiver. + + //HE-KV-1 Missile + #loc_BDArmory_part_bahaHEKV1_title = HE-KV-1 Missile + //The HE-KV-1 (High explosive kill vehicle) is a radar-guided homing missile that uses reaction control thrusters and thrust vectoring to maneuver. This means it is capable of steering towards targets in a vacuum. + #loc_BDArmory_part_bahaHEKV1_description = The HE-KV-1 (High explosive kill vehicle) is a radar-guided homing missile that uses reaction control thrusters and thrust vectoring to maneuver. This means it is capable of steering towards targets in a vacuum. + + //AGM-114 Hellfire Missile + #loc_BDArmory_part_bahaAGM-114_title = AGM-114 Hellfire Missile + //Small, quick, laser guided homing missile. + #loc_BDArmory_part_bahaAGM-114_description = Small, quick, laser guided homing missile. + + //Vulcan (Hidden) + #loc_BDArmory_part_bahaHiddenVulcan_title = Vulcan (Hidden) + //A 6 barrel 20x102mm rotary cannon. 20x102Ammo + #loc_BDArmory_part_bahaHiddenVulcan_description = A 6 barrel 20x102mm rotary cannon. 20x102Ammo + + //Mk83 JDAM Bomb + #loc_BDArmory_part_bahaJdamMk83_title = Mk83 JDAM Bomb + //1000lb GPS-guided bomb. + #loc_BDArmory_part_bahaJdamMk83_description = 1000lb GPS-guided bomb. + + //M102 Howitzer (Radial) + #loc_BDArmory_part_bahaM102Howitzer_title = M102 Howitzer (Radial) + //A radially mounted 105mm gun. CannonShells + #loc_BDArmory_part_bahaM102Howitzer_description =A radially mounted 105mm gun. CannonShells + + //M1 Abrams Cannon + #loc_BDArmory_part_bahaM1Abrams_title = M1 Abrams Cannon + //A 120mm cannon on an armored turret. CannonShells + #loc_BDArmory_part_bahaM1Abrams_description = A 120mm cannon on an armored turret. CannonShells + + //M230 Chain Gun Turret + #loc_BDArmory_part_bahaM230ChainGun_title = M230 Chain Gun Turret + //The M230 Chain Gun is a single-barrel automatic cannon firing 30x173 Ammo high explosive rounds. It is commonly used on attack helicopters. + #loc_BDArmory_part_bahaM230ChainGun_description = The M230 Chain Gun is a single-barrel automatic cannon firing 30x173 Ammo high explosive rounds. It is commonly used on attack helicopters. + + //AGM-65 Maverick Missile + #loc_BDArmory_part_bahaAGM-65_title = AGM-65 Maverick Missile + //Medium yield laser guided air-to-ground missile. + #loc_BDArmory_part_bahaAGM-65_description = Medium yield laser guided air-to-ground missile. + + //Jernas Missile Turret + #loc_BDArmory_part_missileTurretTest_title = Jernas Missile Turret + //A turret capable of holding and firing up to 8 small to medium sized missiles. Comes with an integrated detection and tracking radar. Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_missileTurretTest_description = A turret capable of holding and firing up to 8 small to medium sized missiles. Comes with an integrated detection and tracking radar. Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + + //Mk82 Bomb + #loc_BDArmory_part_bahaMk82Bomb_title = Mk82 Bomb + //500lb unguided bomb. + #loc_BDArmory_part_bahaMk82Bomb_description = 500lb unguided bomb. + + //Mk82 SnakeEye Bomb + #loc_BDArmory_part_bahaMk82BombBrake_title = Mk82 SnakeEye Bomb + //500lb unguided bomb with airbrakes. Use for low altitude bombing. + #loc_BDArmory_part_bahaMk82BombBrake_description = 500lb unguided bomb with airbrakes. Use for low altitude bombing. + + //Oerlikon Millennium Cannon + #loc_BDArmory_part_bahaOMillennium_title = Oerlikon Millennium Cannon + //A turret that fires timed detonation explosive rounds. Suited for close-in air defense. A device at the muzzle end of the barrel measures the exact speed of each round as it is fired, and automatically sets the fuse to detonate the round as it approaches a pre-set distance from the target. Uses 30x173Ammo + #loc_BDArmory_part_bahaOMillennium_description = A turret that fires timed detonation explosive rounds. Suited for close-in air defense. A device at the muzzle end of the barrel measures the exact speed of each round as it is fired, and automatically sets the fuse to detonate the round as it approaches a pre-set distance from the target. Uses 30x173Ammo + + //PAC-3 Intercept Missile + #loc_BDArmory_part_bahaPac-3_title = PAC-3 Intercept Missile + //Medium range, high speed, radar-guided surface to air missile. + #loc_BDArmory_part_bahaPac-3_description = Medium range, high speed, radar-guided surface to air missile. + + //Patriot Launcher Turret + #loc_BDArmory_part_patriotLauncherTurret_title = Patriot Launcher Turret + //A turret capable of holding and firing up to 16 PAC-3 missiles (4 per cannister). Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_patriotLauncherTurret_description = A turret capable of holding and firing up to 16 PAC-3 missiles (4 per cannister). Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + + //Radar Data Receiver + #loc_BDArmory_part_radarDataReceiver_title = Radar Data Receiver + //A module that can display radar contacts via data-link and lock targets through a remote radar, but can not scan or lock by itself. Useful for a hidden missile battery. + #loc_BDArmory_part_radarDataReceiver_description = A module that can display radar contacts via data-link and lock targets through a remote radar, but can not scan or lock by itself. Useful for a hidden missile battery. + + //AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1_title = AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1_description = A forward facing, aerodynamically housed radar. It can scan and lock targets within a 120 degree field of view. It is optimized for air-to-air combat, and has difficulties locking surface targets. + + //AN/APG-63 Inline Radome + #loc_BDArmory_part_bdRadome1inline_title = AN/APG-63 Inline Radome + #loc_BDArmory_part_bdRadome1inline_description = A forward facing, aerodynamically housed radar. It can scan and lock targets within a 120 degree field of view. Make sure the black markings are pointing forward. It is optimized for air-to-air combat, and has difficulties locking surface targets. + + //AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1snub_title = AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1snub_description = A forward facing, aerodynamically housed radar. It can scan and lock targets within a 120 degree field of view. This is a dedicated ground attack version with much better performance against ground targets, but reduced air-to-air capabilities. + + //RBS-15 Cruise Missile + #loc_BDArmory_part_bahaRBS-15Cruise_title = RBS-15 Cruise Missile + //Long distance, multi-platform high-speed cruise missile with boosters. + #loc_BDArmory_part_bahaRBS-15Cruise_description = Long distance, multi-platform high-speed cruise missile with boosters. + + //Adjustable Rotary Bomb Rack + #loc_BDArmory_part_bdRotBombBay_title = Adjustable Rotary Bomb Rack + //An adjustable rotary bomb rack. The yellow arrow should be pointing in the direction of weapon release. Missiles or bombs only. One per rail only. + #loc_BDArmory_part_bdRotBombBay_description = An adjustable rotary bomb rack. The yellow arrow should be pointing in the direction of weapon release. Missiles or bombs only. One per rail only. + + //S-8KOM Rocket Pod + #loc_BDArmory_part_bahaS-8Launcher_title = S-8KOM Rocket Pod + //Holds and fires 23 unguided S-8KOM rockets. It has an aerodynamic nose cone. + #loc_BDArmory_part_bahaS-8Launcher_description = Holds and fires 23 unguided S-8KOM rockets. It has an aerodynamic nose cone. + + //AIM-9 Sidewinder Missile + #loc_BDArmory_part_bahaAim9_title = AIM-9 Sidewinder Missile + //Short range heat seeking missile. + #loc_BDArmory_part_bahaAim9_description = Short range heat seeking missile. + + //Small High Explosive Warhead + #loc_BDArmory_part_bdWarheadSmall_title = Small High Explosive Warhead + //A missile nose cone packed with explosives. + #loc_BDArmory_part_bdWarheadSmall_description = A missile nose cone packed with explosives. + + //Smoke Countermeasure Pod + #loc_BDArmory_part_bahaSmokeCmPod_title = Smoke Countermeasure Pod + //Fires smoke-screen countermeasures for occluding laser points. + #loc_BDArmory_part_bahaSmokeCmPod_description = Fires smoke-screen countermeasures for occluding laser points. + + //FLIR Targeting Ball + #loc_BDArmory_part_bahaFlirBall_title = FLIR Targeting Ball + //A ball camera used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + #loc_BDArmory_part_bahaFlirBall_description = A ball camera used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + + //AN/AAQ-28 Targeting Pod + #loc_BDArmory_part_bahaCamPod_title = AN/AAQ-28 Targeting Pod + //A targeting pod used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + #loc_BDArmory_part_bahaCamPod_description = A targeting pod used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + + //Tow Launcher + #loc_BDArmory_part_towLauncherTurret_title = Tow Launcher + //A turret capable of holding and firing up to 4 TOW missiles. Warranty void if anything except TOW missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_towLauncherTurret_description = A turret capable of holding and firing up to 4 TOW missiles. Warranty void if anything except TOW missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + + //BGM-71 Tow Missile + #loc_BDArmory_part_bahaTowMissile_title = BGM-71 Tow Missile + //Short distance, laser beam-riding, wireless anti-tank missile. + #loc_BDArmory_part_bahaTowMissile_description = Short distance, laser beam-riding, wireless anti-tank missile. + + //Weapon Manager + #loc_BDArmory_part_missileController_title = Weapon Manager + //Cycle through missiles/bombs and fire them with a single button. + #loc_BDArmory_part_missileController_description = Cycle through missiles/bombs and fire them with a single button. + + //BDAsonarPod1A + #loc_BDArmory_part_BDAsonarPod1A_title = BDA MK1 Sonar Pod + #loc_BDArmory_part_BDAsonarPod1A_description = BDA MK1 Sonar Pod can only detect splashed and submerged vessels mount below waterline for best results. As a hull-mounted sonar it has limited range and sensitivity only. + + //StingRayBDATorpedo + #loc_BDArmory_part_StingRayBDATorpedo_title = Sting Ray BDA LightWeight Torpedo + #loc_BDArmory_part_StingRayBDATorpedo_description = Sting Ray Light Weight Torpedo Ship launch, and heli launch airdrop do not use in submarines. Interesting fact, you can fit 16 of these in a pac launcher, though using them in such a device without proper training has been the cause of much weeping and letters written. + + //SaturnAL31 + #loc_BDArmory_part_SaturnAL31_title = Saturn AL-31FM1 Afterburning Jet Engine + //A high performance jet engine with a variable geometry thrust vectoring nozzle and an afterburner for extra thrust. Based on the highly popular J-404 engine, KTech engineers saw the potential of (highly) modifying the commercial variant into a formidable powerplant for military use. After seeing the potential of the engine, the BDAc group immediately licensed it for their new MkIII test drone. + #loc_BDArmory_part_SaturnAL31_description = A high performance jet engine with a variable geometry thrust vectoring nozzle and an afterburner for extra thrust. Based on the highly popular J-404 engine, KTech engineers saw the potential of (highly) modifying the commercial variant into a formidable powerplant for military use. After seeing the potential of the engine, the BDAc group immediately licensed it for their new MkIII test drone. + } +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Localization/localization-es-es.cfg b/BDArmory/Distribution/GameData/BDArmory/Localization/localization-es-es.cfg new file mode 100644 index 000000000..1a14b7576 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Localization/localization-es-es.cfg @@ -0,0 +1,336 @@ +Localization +{ + es-es + { + #loc_BDArmory_modname = BD Armory + + #loc_BDArmory_agent_title = Dinámicas Bahamuto. + #loc_BDArmory_agent_description = Fabricante líder de armas y municiones militares. La compañía también es ocasionalmente contratada por el programa espacial para soluciones de ingeniería avanzadas o únicas. + #loc_BDArmory_part_manufacturer = Dinámicas Bahamuto. + + //Vulcan Turret + #loc_BDArmory_part_bahaGatlingGun_title = Torreta Vulcan + //A 6 barrel 20x102mm rotary cannon. + #loc_BDArmory_part_bahaGatlingGun_description = Un cañón rotatorio 20x102mm de 6 cañónes. + + //.50cal Turret + #loc_BDArmory_part_bahaTurret_title = Torreta calibre .50 + //A dual barrel .50 cal machine gun. + #loc_BDArmory_part_bahaTurret_description = Una ametralladora de calibre .50 con doble cañón. + + //USAF Airborne Laser + #loc_BDArmory_part_bahaABL_title = USAF Laser Aerotransportado + //A high powered laser for setting things on fire. Uses 350 electric charge per second. + #loc_BDArmory_part_bahaABL_description = Un láser de alta potencia para poner las cosas en llamas. Utiliza 350 de carga eléctrica por segundo. + + //Adjustable Missile Rail + #loc_BDArmory_part_bahaAdjustableRail_title = Misil Riel Ajustable + //A rail for mounting missiles. + #loc_BDArmory_part_bahaAdjustableRail_description = Un riel para el montaje de misiles. + + //AGM-86C Cruise Missile + #loc_BDArmory_part_bahaAgm86B_title = Misil de crucero AGM-86C + //Long distance, sub-sonic, air-launched, GPS-guided cruise missile. This missile has no booster, so it must be launched while airborne at cruising speed. + #loc_BDArmory_part_bahaAgm86B_description = Misil de crucero de larga distancia, subsónico, lanzado al aire, guiado por GPS. Este misil no tiene refuerzo, por lo que debe ser lanzado mientras está en el aire a la velocidad de crucero. + + //AIM-120 AMRAAM Missile + #loc_BDArmory_part_bahaAim120_title = Misil AIM-120 AMRAAM + //Medium range radar guided homing missile. + #loc_BDArmory_part_bahaAim120_description = Misil guiado de radar de rango medio. + + //AI Pilot Flight Computer + #loc_BDArmory_part_bdPilotAI_title = Computadora de vuelo piloto de Inteligencia Artificial + //Flies your plane on combat air patrol missions without using your hands. Tune the values based on your plane's unique flight characteristics. Please activate engines manually. Works in conjunction with a weapon manager in guard mode (attach and configure separately). (EXPERIMENTAL) + #loc_BDArmory_part_bdPilotAI_description = Vuela su avión en misiones de patrulla aérea de combate sin usar sus manos. Ajuste los valores según las características de vuelo únicas de su avión. Por favor, active los motores manualmente. Funciona junto con un administrador de armas en modo de guardia (adjuntar y configurar por separado). (EXPERIMENTAL) + + //20mm Ammunition Box + #loc_BDArmory_part_baha20mmAmmo_title = Caja de municiones de 20mm + //Ammo box containing 650 20x102mm rounds. + #loc_BDArmory_part_baha20mmAmmo_description = Caja de munición que contiene 650 cartuchos de 20x102mm. + + //30mm Ammunition Box + #loc_BDArmory_part_baha30mmAmmo_title = Caja de municiones de 30mm + //Ammo box containing 600 30x173mm rounds. + #loc_BDArmory_part_baha30mmAmmo_description = Caja de munición que contiene 600 cartuchos de 30x173mm. + + //50cal Ammunition Box + #loc_BDArmory_part_baha50CalAmmo_title = Caja de munición de calibre 50 + //Ammo box containing 1200 .50 cal rounds. + #loc_BDArmory_part_baha50CalAmmo_description = Caja de munición que contiene 1200 cartuchos de calibre .50. + + //Universal Ammo Box (Legacy) + #loc_BDArmory_part_UniversalAmmoBoxBDA_title = Caja de munición universal (Legacy) + //(Obsolete - DO NOT USE - Requires Fire Spitter) Scalable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) NOTE: this part still requires Fire Spitter, and is here for backwards compatability. Use the new UniversalAmmo part going forward. + #loc_BDArmory_part_UniversalAmmoBoxBDA_description = (Obsoleto - NO USE - Requiere FireSpitter) La caja de Munición escalable que contiene cualquier munición que quieras poner en ella, contiene una cantidad seleccionable de cada tipo de munición de hasta 16'1 pulgadas que se usa actualmente en KSP en asociación con BDAc. Se pueden agregar tipos extra bajo petición (no munición de fantasía por favor) NOTA: esta parte aún requiere FireSpitter, y está aquí para compatibilidad con versiones anteriores. Use la nueva parte de Caja de munición universal en el futuro. + + //Universal Ammo Box + #loc_BDArmory_part_BDAcUniversalAmmoBox_title = Caja de munición universal + //Scaleable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) + #loc_BDArmory_part_BDAcUniversalAmmoBox_description = La caja de munición escalable que contiene cualquier munición que quieras poner en ella, contiene una cantidad seleccionable de cada tipo de munición de hasta 16'1 pulgadas que se usa actualmente en KSP en asociación con BDAc Se pueden agregar tipos extra bajo petición (no munición de fantasía por favor) + + //Cannon Ammunition Box + #loc_BDArmory_part_bahaCannonShellBox_title = Caja de munición de cañón + //Ammo box containing 10 cannon shells. + #loc_BDArmory_part_bahaCannonShellBox_description = Caja de munición que contiene 10 proyectiles de cañón. + + //BD 1x1 slope Armor + #loc_BDArmory_part_BD1x1slopeArmor_title = BD 1x1 Armadura con pendiente + //A sturdy 1x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD1x1slopeArmor_description = Una robusta placa de armadura con pendiente de 1x1, perfecta para construir todo tipo de cosas. PD. no flota + + //BD 2x1 slope Armor + #loc_BDArmory_part_BD2x1slopeArmor_title = BD 2x1 Armadura con pendiente + //A sturdy 2x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD2x1slopeArmor_description = Una robusta placa de armadura con pendiente 2x1, perfecta para construir todo tipo de cosas. PD. no flota + + //BD 1x1 panel Armor + #loc_BDArmory_part_BD1x1panelArmor_title = BD 1x1 panel Armadura + //A sturdy 1x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD1x1panelArmor_description = Una robusta placa de armadura de 1x1, perfecta para construir todo tipo de cosas. PD. no flota + + //BD 2x1 panel Armor + #loc_BDArmory_part_BD2x1panelArmor_title = BD 2x1 panel Armadura + //A sturdy 2x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD2x1panelArmor_description = Una robusta placa de armadura de 2x1, perfecta para construir todo tipo de cosas. PD. no flota + + //BD 3x1 panel Armor + #loc_BDArmory_part_BD3x1panelArmor_title = BD 3x1 panel Armadura + //A sturdy 3x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD3x1panelArmor_description = Una robusta placa de armadura de 3x1, perfecta para construir todo tipo de cosas. PD. no flota + + //BD 4x1 panel Armor + #loc_BDArmory_part_BD4x1panelArmor_title = BD 4x1 panel Armadura + //A sturdy 4x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD4x1panelArmor_description = Una robusta placa de armadura de 4x1, perfecta para construir todo tipo de cosas. PD. no flota + + //AWACS Detection Radar + #loc_BDArmory_part_awacsRadar_title = AWACS Radar de detección + //A large radar capable of detecting objects from a long distance. This radar does NOT have the capability of tracking or locking targets. + #loc_BDArmory_part_awacsRadar_description = Un gran radar capaz de detectar objetos desde una distancia larga. Este radar NO tiene la capacidad de rastrear o bloquear objetivos. + + //Modular Missile Guidance (EXPERIMENTAL) + #loc_BDArmory_part_bdammGuidanceModule_title = Orientación de misiles modulares (EXPERIMENTAL) + //A missile guidance computer. Manually tune steering settings to craft's unique flight characteristics. Select a guidance mode. Select a target then enable guidance. Activate engines and stages manually. (EXPERIMENTAL) + #loc_BDArmory_part_bdammGuidanceModule_description = Una computadora de guía de misiles. Ajuste manualmente las configuraciones de dirección a las características de vuelo únicas de la nave. Seleccione un modo de guía. Seleccione un objetivo y luego habilite la guía. Activar motores y etapas manualmente. (EXPERIMENTAL) + + //Browning .50cal AN/M2 + #loc_BDArmory_part_bahaBrowningAnm2_title = Browning calibre .50 AN/M3 + //An old fixed .50 cal machine gun 50cal ammo + #loc_BDArmory_part_bahaBrowningAnm2_description = Una vieja ametralladora fija calibre .50 + + //CBU-87 Cluster Bomb + #loc_BDArmory_part_bahaClusterBomb_title = CBU-87 Bomba de racimo + //This bomb splits open and deploys many small bomblets at a certain altitude. + #loc_BDArmory_part_bahaClusterBomb_description = Esta bomba se abre y despliega muchas pequeñas bombas a cierta altura. + + //Chaff Dispenser + #loc_BDArmory_part_bahaChaffPod_title = Dispensador de señuelos + //Drops chaff for confusing or breaking radar locks. + #loc_BDArmory_part_bahaChaffPod_description = Suelta señuielos para confundir o romper las fijaciones de radar. + + //Flare Dispenser + #loc_BDArmory_part_bahaCmPod_title = Dispensador de bengalas + //Drops flares for confusing heat-seeking missiles. + #loc_BDArmory_part_bahaCmPod_description = Suelta bengalas para confundir misiles de búsqueda de calor. + + //AN/ALQ-131 ECM Jammer + #loc_BDArmory_part_bahaECMJammer_title = AN/ALQ-131 ECM Jammer + //This electronic device makes it harder for radars to lock onto your vehicle, and increases your chances of breaking the lock. + #loc_BDArmory_part_bahaECMJammer_description = Este dispositivo electrónico hace que sea más difícil para los radares engancharse a su vehículo, y aumenta sus posibilidades de romper el bloqueo. + + //GAU-8 30x173mm Cannon + #loc_BDArmory_part_bahaGau-8_title = Cañón GAU-8 30x173mm + //A 7 barrel 30mm rotary cannon. + #loc_BDArmory_part_bahaGau-8_description = Un cañón giratorio con 7 cañones de 30mm. + + //Goalkeeper CIWS + #loc_BDArmory_part_bahaGoalKeeper_title = Cancerbero CIWS + #loc_BDArmory_part_bahaGoalKeeper_description = Un cañón giratorio con 7 cañones de 30mm con rango de giro completo. Las rondas altamnete explosivas de 30mm se detonan a la distancia establecida, pero esta arma no cuenta con sincronización automática de fusibles. Tiene su propio radar de detección y seguimiento, aunque solo es efectivo a corta distancia y no reemplaza un radar de búsqueda de suficiente espacio. + + //GoalkeeperMk1 CIWS + #loc_BDArmory_part_GoalKeeperBDAcMk1_title = Cancerbero Mk1 CIWS + #loc_BDArmory_part_GoalKeeperBDAcMk1_description = Un cañón giratorio con 7 cañones de 30mm con rango giratorio completo. Esta versión MK 1 fue encontrada debajo de una lona en un campo fangoso, perfecta para milicias atadas en efectivo y gobiernos furtivos (versión cheapskate). Sin radar o equipo de detección esta torre requiere que la información de objetivo sea alimentada desde una fuente alternativa. (Alguien señalando y gritando "disparen a eso" ha sido encontrado marginalmente efectivo debido al ruido excesivo producido cuando el arma se dispara) Las rondas explosivas de 30mm se auto detonan cuando pierden interés en volar, pero esta arma no cuenta con sincronización automática de fusibles. + + //Goalkeeper MK2 CIWS + #loc_BDArmory_part_BDAcGKmk2_title = Cancerbero MK2 CIWS + #loc_BDArmory_part_BDAcGKmk2_description = Un cañón giratorio con 7 cañones de 30mm con rango giratorio completo. Esta versión MK2 fue encontrada cubierta de pintura en la parte posterior del hangar en la antigua KSC, desarrollado a partir de MK1 para reducir la incidencia de pérdida de audición entre los primeros indicadores de objetivos. Este MK2 tiene algunas pequeñas ventajas con respecto al MK1, equipado con una red de infrarrojos y un receptor de datos de radar. Las rondas de alto explosivo de 30x173 mm son solo una ligera mejora con respecto a la munición MK1 ya que al menos tardan un poco más en perder el interés en volar y así tienen una buena posibilidad de alcanzar el objetivo, pero esta arma nunca estuvo equipada para ofrecer un cronometraje automático de fusibles. + + //TWS Locking Radar + #loc_BDArmory_part_scanLockRadar1_title = TWS Radar de bloqueo + #loc_BDArmory_part_scanLockRadar1_description = Esta unidad tiene un radar de detección de alcance medio y un radar de seguimiento de objetivos incorporado. Este radar es capaz de bloquear objetivos, y continuará escaneando mientras rastrea el objetivo bloqueado (TWS - Track While Scan). Está optimizado para búsqueda y seguimiento aéreo, y tiene dificultades para detectar y rastrear objetivos de superficie. + + //Large Detection Radar + #loc_BDArmory_part_scanLargeRadar_title = Gran radar de detección + #loc_BDArmory_part_scanLargeRadar_description = Un gran radar capaz de detectar objetos desde una distancia larga. Este radar NO tiene la capacidad de rastrear o bloquear objetivos. Está optimizado para la búsqueda aérea y tiene dificultades para detectar objetivos de superficie. + + //Hydra-70 Rocket Pod + #loc_BDArmory_part_bahaH70Launcher_title = Cápsula de cohete Hydra-70 + //Holds and fires 19 unguided Hydra-70 rockets. + #loc_BDArmory_part_bahaH70Launcher_description = Sostiene y dispara 19 cohetes Hydra-70 no guiados. + + //Hydra-70 Rocket Turret + #loc_BDArmory_part_bahaH70Turret_title = Torreta de cohetes Hydra-70 + //Turret pod that holds and fires 32 unguided Hydra-70 rockets. + #loc_BDArmory_part_bahaH70Turret_description = Torreta que sostiene y dispara 32 cohetes Hydra-70 no guiados. + + //AGM-88 HARM Missile + #loc_BDArmory_part_bahaHarm_title = Misil AGM-88 HARM + //High-speed anti-radiation missile. This missile will home in on radar sources detected by the Radar Warning Receiver. + #loc_BDArmory_part_bahaHarm_description = Misil anti-radiación de alta velocidad. Este misil se dirigirá a las fuentes de radar detectadas por el receptor de advertencia de radar. + + //HE-KV-1 Missile + #loc_BDArmory_part_bahaHEKV1_title = Misilv HE-KV-1 + //The HE-KV-1 (High explosive kill vehicle) is a radar-guided homing missile that uses reaction control thrusters and thrust vectoring to maneuver. This means it is capable of steering towards targets in a vacuum. + #loc_BDArmory_part_bahaHEKV1_description = El HE-KV-1 (Vehículo de alta extinción de explosivos) es un misil guiado por radar que utiliza propulsores de control de reacción y vector de empuje para maniobrar. Esto significa que es capaz de dirigirse hacia los objetivos en el vacío. + + //AGM-114 Hellfire Missile + #loc_BDArmory_part_bahaAGM-114_title = Misil AGM-114 Hellfire + //Small, quick, laser guided homing missile. + #loc_BDArmory_part_bahaAGM-114_description = Pequeño, rápido, dirigido guiado por láser misil. + + //Vulcan (Hidden) + #loc_BDArmory_part_bahaHiddenVulcan_title = Vulcan (Oculto) + //A 6 barrel 20x102mm rotary cannon. 20x102Ammo + #loc_BDArmory_part_bahaHiddenVulcan_description = Un cañón rotativo con 6 cañones 20x102mm. Munición 20x102 + + //Mk83 JDAM Bomb + #loc_BDArmory_part_bahaJdamMk83_title = Bomba Mk83 JDAM + //1000lb GPS-guided bomb. + #loc_BDArmory_part_bahaJdamMk83_description = Bomba guiada por GPS de 1000 lb + + //M102 Howitzer (Radial) + #loc_BDArmory_part_bahaM102Howitzer_title = M102 Howitzer (Radial) + //A radially mounted 105mm gun. CannonShells + #loc_BDArmory_part_bahaM102Howitzer_description = Un cañon de 105mm montado radialmente. Proyectiles de cañón + + //M1 Abrams Cannon + #loc_BDArmory_part_bahaM1Abrams_title = Cañón M1 Abrams + //A 120mm cannon on an armored turret. CannonShells + #loc_BDArmory_part_bahaM1Abrams_description = Un cañón de 120mm en una torreta blindada. Proyectiles de cañón + + //M230 Chain Gun Turret + #loc_BDArmory_part_bahaM230ChainGun_title = Torreta de cañón de cadena M230 + //The M230 Chain Gun is a single-barrel automatic cannon firing 30x173 Ammo high explosive rounds. It is commonly used on attack helicopters. + #loc_BDArmory_part_bahaM230ChainGun_description = La ametralladora de cadena M230 es un cañón automático de cañón único que dispara munición de alto explosivo de 30x173. Se usa comúnmente en helicópteros de ataque. + + //AGM-65 Maverick Missile + #loc_BDArmory_part_bahaAGM-65_title = Misil Maverick AGM-65 + //Medium yield laser guided air-to-ground missile. + #loc_BDArmory_part_bahaAGM-65_description = Misil aire-tierra guiado por láser de rendimiento medio. + + //Jernas Missile Turret + #loc_BDArmory_part_missileTurretTest_title = Torreta de misiles Jernas + //A turret capable of holding and firing up to 8 small to medium sized missiles. Comes with an integrated detection and tracking radar. Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_missileTurretTest_description = Una torreta capaz de sostener y disparar hasta 8 misiles de tamaño pequeño a mediano. Viene con un radar integrado de detección y seguimiento. Garantía nula si se monta algo excepto misiles. Para habilitar la torreta, selecciona el misil montado del administrador de armas. + + //Mk82 Bomb + #loc_BDArmory_part_bahaMk82Bomb_title = Bomba Mk82 + //500lb unguided bomb. + #loc_BDArmory_part_bahaMk82Bomb_description = Bomba no guiada de 500 lb. + + //Mk82 SnakeEye Bomb + #loc_BDArmory_part_bahaMk82BombBrake_title = Bomba Mk82 SnakeEye + //500lb unguided bomb with airbrakes. Use for low altitude bombing. + #loc_BDArmory_part_bahaMk82BombBrake_description = Bomba no guiada de 500 libras con aerofrenos. Usar para bombardeos a baja altura. + + //Oerlikon Millennium Cannon + #loc_BDArmory_part_bahaOMillennium_title = Cañón Millennium Oerlikon + //A turret that fires timed detonation explosive rounds. Suited for close-in air defense. A device at the muzzle end of the barrel measures the exact speed of each round as it is fired, and automatically sets the fuse to detonate the round as it approaches a pre-set distance from the target. Uses 30x173Ammo + #loc_BDArmory_part_bahaOMillennium_description = Una torreta que dispara rondas explosivas de detonación programadas. Adecuado para la defensa aérea de cerca. Un dispositivo en el extremo del cañón del cañón mide la velocidad exacta de cada ronda cuando se dispara, y establece automáticamente el fusible para detonar la ronda a medida que se acerca a una distancia predeterminada del objetivo. Usa munición de 30x173 + + //PAC-3 Intercept Missile + #loc_BDArmory_part_bahaPac-3_title = Misil de interceptación PAC-3 + //Medium range, high speed, radar-guided surface to air missile. + #loc_BDArmory_part_bahaPac-3_description = Rango medio, alta velocidad, misil tierra-aire guiado por radar. + + //Patriot Launcher Turret + #loc_BDArmory_part_patriotLauncherTurret_title = Torreta Patriot Launcher + //A turret capable of holding and firing up to 16 PAC-3 missiles (4 per cannister). Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_patriotLauncherTurret_description = Una torreta capaz de sostener y disparar hasta 16 misiles PAC-3 (4 por recipiente). Garantía nula si se monta algo excepto misiles. Para habilitar la torreta, selecciona el misil montado del administrador de armas. + + //Radar Data Receiver + #loc_BDArmory_part_radarDataReceiver_title = Receptor de datos de radar + //A module that can display radar contacts via data-link and lock targets through a remote radar, but can not scan or lock by itself. Useful for a hidden missile battery. + #loc_BDArmory_part_radarDataReceiver_description = Un módulo que puede mostrar los contactos del radar a través del enlace de datos y bloquear objetivos a través de un radar remoto, pero no puede escanear o bloquear por sí mismo. Útil para una batería de misiles oculta. + + //AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1_title = AN/APG-63 Radomo + #loc_BDArmory_part_bdRadome1_description = Un radar orientado hacia adelante, aerodinámicamente alojado. Puede escanear y bloquear objetivos dentro de un campo de visión de 120 grados. Está optimizado para el combate aire-aire y tiene dificultades para bloquear objetivos de superficie. + + //AN/APG-63 Inline Radome + #loc_BDArmory_part_bdRadome1inline_title = AN / APG-63 Radomo en línea + #loc_BDArmory_part_bdRadome1inline_description = Un radar orientado hacia adelante, aerodinámicamente alojado. Puede escanear y bloquear objetivos dentro de un campo de visión de 120 grados. Asegúrese de que las marcas negras estén apuntando hacia adelante. Está optimizado para el combate aire-aire y tiene dificultades para bloquear objetivos de superficie. + + //AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1snub_title = AN/APG-63 Radomo + #loc_BDArmory_part_bdRadome1snub_description = Un radar orientado hacia adelante, aerodinámicamente alojado. Puede escanear y bloquear objetivos dentro de un campo de visión de 120 grados. Esta es una versión de ataque terrestre dedicada con un rendimiento mucho mejor contra objetivos terrestres, pero con capacidades reducidas aire-aire. + + //RBS-15 Cruise Missile + #loc_BDArmory_part_bahaRBS-15Cruise_title = Misil de crucero RBS-15 + //Long distance, multi-platform high-speed cruise missile with boosters. + #loc_BDArmory_part_bahaRBS-15Cruise_description = Larga distancia, misil de crucero multiplataforma de alta velocidad con aceleradores. + + //Adjustable Rotary Bomb Rack + #loc_BDArmory_part_bdRotBombBay_title = Estante de bomba giratorio ajustable + //An adjustable rotary bomb rack. The yellow arrow should be pointing in the direction of weapon release. Missiles or bombs only. One per rail only. + #loc_BDArmory_part_bdRotBombBay_description = Un estante de bomba rotativo ajustable. La flecha amarilla debe apuntar en la dirección del lanzamiento del arma. Misiles o bombas solamente. Una por carril solamente. + + //S-8KOM Rocket Pod + #loc_BDArmory_part_bahaS-8Launcher_title = Cápsula de cohetes S-8KOM + //Holds and fires 23 unguided S-8KOM rockets. It has an aerodynamic nose cone. + #loc_BDArmory_part_bahaS-8Launcher_description = Sostiene y dispara 23 cohetes S-8KOM no guiados. Tiene un cono de nariz aerodinámico. + + //AIM-9 Sidewinder Missile + #loc_BDArmory_part_bahaAim9_title = Misil Sidewinder AIM-9 + //Short range heat seeking missile. + #loc_BDArmory_part_bahaAim9_description = Misil de búsqueda de calor de corto alcance. + + //Small High Explosive Warhead + #loc_BDArmory_part_bdWarheadSmall_title = Pequeño gran ojiva explosiva + //A missile nose cone packed with explosives. + #loc_BDArmory_part_bdWarheadSmall_description = Un cono de punta de misiles lleno de explosivos. + + //Smoke Countermeasure Pod + #loc_BDArmory_part_bahaSmokeCmPod_title = Vaina de contramedidas de humo + //Fires smoke-screen countermeasures for occluding laser points. + #loc_BDArmory_part_bahaSmokeCmPod_description = Incendia contramedidas para pantallas de humo para ocluir puntos de láser. + + //FLIR Targeting Ball + #loc_BDArmory_part_bahaFlirBall_title = Bola de orientación FLIR + //A ball camera used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + #loc_BDArmory_part_bahaFlirBall_description = Una cámara de bolas utilizada para la orientación y la vigilancia. Equipada con una cámara de alta resolución con estabilización de superficie y horizonte, y un láser infrarrojo para pintar objetivos, esta cápsula le permite encontrar rápidamente y bloquear objetivos a tierra para los misiles. + + //AN/AAQ-28 Targeting Pod + #loc_BDArmory_part_bahaCamPod_title = AN / AAQ-28 Grupo de orientación + //A targeting pod used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + #loc_BDArmory_part_bahaCamPod_description = Una vaina de orientación utilizado para la orientación y vigilancia. Equipada con una cámara de alta resolución con estabilización de superficie y horizonte, y un láser infrarrojo para pintar objetivos, Esta cápsula le permite encontrar rápidamente y bloquear objetivos a tierra para los misiles. + + //Tow Launcher + #loc_BDArmory_part_towLauncherTurret_title = Lanzador de remolque + //A turret capable of holding and firing up to 4 TOW missiles. Warranty void if anything except TOW missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_towLauncherTurret_description = Una torreta capaz de sostener y disparar hasta 4 misiles TOW. La garantía está anulada si se monta algo, excepto los misiles TOW. Para habilitar la torreta, selecciona el misil montado del administrador de armas. + + //BGM-71 Tow Missile + #loc_BDArmory_part_bahaTowMissile_title = BGM-71 misil de remolque TOW + //Short distance, laser beam-riding, wireless anti-tank missile. + #loc_BDArmory_part_bahaTowMissile_description = Distancia corta, rayo láser, misiles antitanque inalámbricos. + + //Weapon Manager + #loc_BDArmory_part_missileController_title = Gestor de armas + //Cycle through missiles/bombs and fire them with a single button. + #loc_BDArmory_part_missileController_description = El ciclo a través de misiles/bombas y los dispara con un botón solo. + + //BDAsonarPod1A + #loc_BDArmory_part_BDAsonarPod1A_title = Vaina del radar ultrasónico de BDA MK1 + #loc_BDArmory_part_BDAsonarPod1A_description = El sonar BDA MK1 solo puede detectar recipientes a flote y sumergidos que se montan debajo de la línea de flotación para obtener mejores resultados. Como un sonar montado en el casco, tiene un alcance y sensibilidad limitados. + + //StingRayBDATorpedo + #loc_BDArmory_part_StingRayBDATorpedo_title = Sting Ray BDA Torpedo Ligero + #loc_BDArmory_part_StingRayBDATorpedo_description = El torpedo liviano "Sting Ray" es lanzado por barcos y helicópteros. No lo uses como un torpedo submarino. De hecho, puedes incluir 16 de estos en un lanzador de paquetes, aunque usarlos en un dispositivo sin el entrenamiento adecuado ha sido la causa de mucho llanto y cartas escritas. + + //SaturnAL31 + #loc_BDArmory_part_SaturnAL31_title = Motor Jet Saturno AL-31FM1 de postcombustión + //A high performance jet engine with a variable geometry thrust vectoring nozzle and an afterburner for extra thrust. Based on the highly popular J-404 engine, KTech engineers saw the potential of (highly) modifying the commercial variant into a formidable powerplant for military use. After seeing the potential of the engine, the BDAc group immediately licensed it for their new MkIII test drone. + #loc_BDArmory_part_SaturnAL31_description = Un motor a reacción de alto rendimiento con una boquilla de vectorización de empuje de geometría variable y una postcombustión para empuje adicional. Con base en el popular motor J-404, los ingenieros de KTech vieron el potencial de (altamente) modificar la variante comercial en una planta poderosa para uso militar. Después de ver el potencial del motor, el grupo BDAc inmediatamente lo licenció para su nuevo drone de prueba MkIII. + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Localization/localization-zh-cn.cfg b/BDArmory/Distribution/GameData/BDArmory/Localization/localization-zh-cn.cfg new file mode 100644 index 000000000..f13d3ddac --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Localization/localization-zh-cn.cfg @@ -0,0 +1,339 @@ +Localization +{ + zh-cn + { + #loc_BDArmory_modname = BD Armory + + #loc_BDArmory_agent_title = 巴哈姆特动力 + #loc_BDArmory_agent_description = 军用武器与弹药业界的领军品牌。该公司同事也和太空计划有长期合作关系,为其提供独特的工程解决方案。 + #loc_BDArmory_part_manufacturer = Bahamuto Dynamics + + //Vulcan Turret + #loc_BDArmory_part_bahaGatlingGun_title = “火神”炮塔 + //A 6 barrel 20x102mm rotary cannon. + #loc_BDArmory_part_bahaGatlingGun_description = 六管20x102mm旋转机炮炮塔。 + + //.50cal Turret + #loc_BDArmory_part_bahaTurret_title = .50口径机枪塔 + //A dual barrel .50 cal machine gun. + #loc_BDArmory_part_bahaTurret_description = 双管.50口径机枪。 + + //USAF Airborne Laser + #loc_BDArmory_part_bahaABL_title = 美国空军空基激光器 + //A high powered laser for setting things on fire. Uses 350 electric charge per second. + #loc_BDArmory_part_bahaABL_description = 用于点燃目标的高能激光器。每秒耗电350单位。 + + //Adjustable Missile Rail + #loc_BDArmory_part_bahaAdjustableRail_title = 可调节导弹挂架 + //A rail for mounting missiles. + #loc_BDArmory_part_bahaAdjustableRail_description = 用于安装导弹的导轨挂架。 + + //AGM-86C Cruise Missile + #loc_BDArmory_part_bahaAgm86B_title = AGM-86C巡航导弹 + //Long distance, sub-sonic, air-launched, GPS-guided cruise missile. This missile has no booster, so it must be launched while airborne at cruising speed. + #loc_BDArmory_part_bahaAgm86B_description = 长射程亚音速空射GPS制导巡航导弹。该导弹没有助推器,所以必须在巡航速度以上从空中发射。 + + //AIM-120 AMRAAM Missile + #loc_BDArmory_part_bahaAim120_title = AIM-120先进中程空对空导弹 + //Medium range radar guided homing missile. + #loc_BDArmory_part_bahaAim120_description = 中距雷达制导导弹。 + + //AI Pilot Flight Computer + #loc_BDArmory_part_bdPilotAI_title = AI自动驾驶飞控计算机 + //Flies your plane on combat air patrol missions without using your hands. Tune the values based on your plane's unique flight characteristics. Please activate engines manually. Works in conjunction with a weapon manager in guard mode (attach and configure separately). (EXPERIMENTAL) + #loc_BDArmory_part_bdPilotAI_description = 在空战和巡逻等飞行任务中解放你的双手!请根据你的飞机实际性能调节各项飞行参数,手动启动引擎。在防卫模式下可以与武器管理器(需要另外安装和设置)协同运作。(实验功能) + + //20mm Ammunition Box + #loc_BDArmory_part_baha20mmAmmo_title = 20mm弹药箱 + //Ammo box containing 650 20x102mm rounds. + #loc_BDArmory_part_baha20mmAmmo_description = 装有650发20x102mm弹药的弹药箱。 + + //30mm Ammunition Box + #loc_BDArmory_part_baha30mmAmmo_title = 30mm弹药箱 + //Ammo box containing 600 30x173mm rounds. + #loc_BDArmory_part_baha30mmAmmo_description = 装有600发30x173mm弹药的弹药箱。 + + //50cal Ammunition Box + #loc_BDArmory_part_baha50CalAmmo_title = .50弹药箱 + //Ammo box containing 1200 .50 cal rounds. + #loc_BDArmory_part_baha50CalAmmo_description = 装有1200发.50口径弹药的弹药箱。 + + //Universal Ammo Box (Legacy) + #loc_BDArmory_part_UniversalAmmoBoxBDA_title = 通用弹药箱(遗产) + //(Obsolete - DO NOT USE - Requires Fire Spitter) Scaleable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added uponn request (no fantasy ammo please). NOTE: this part still requires Fire Spitter, and is here for backwards compatability. Use the new Universal Ammo Box going forward + #loc_BDArmory_part_UniversalAmmoBoxBDA_description = (过时 - 请勿使用 - 需要火Spitter)可以装入任何所需弹药而且尺寸可调的弹药箱,容量可变内容可选,最大可以装入16.1英寸口径弹药。支持的弹药包括现今用于BDAc的所有自带以及附加种类,需要添加新种类请与我们联系(不存在的弹药不行谢谢)。注意:此部分仍需要火Spitter,此处是为了向后兼容。 使用新的通用弹药盒向前发展。 + + //Universal Ammo Box + #loc_BDArmory_part_BDAcUniversalAmmoBox_title = 通用弹药箱 + //Scaleable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added uponn request (no fantasy ammo please) + #loc_BDArmory_part_BDAcUniversalAmmoBox_description = 可以装入任何所需弹药而且尺寸可调的弹药箱,容量可变内容可选,最大可以装入16.1英寸口径弹药。支持的弹药包括现今用于BDAc的所有自带以及附加种类,需要添加新种类请与我们联系(不存在的弹药不行谢谢)。 + + //Cannon Ammunition Box + #loc_BDArmory_part_bahaCannonShellBox_title = 火炮弹药箱 + //Ammo box containing 10 cannon shells. + #loc_BDArmory_part_bahaCannonShellBox_description = 装有10发火炮弹药(CannonShells)的弹药箱。 + + //BD 1x1 slope Armor + #loc_BDArmory_part_BD1x1slopeArmor_title = BD 1x1斜面装甲 + //A sturdy 1x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD1x1slopeArmor_description = 一块结实的1x1斜面装甲板,适用于建造各种产品。注:并不能漂浮。 + + //BD 2x1 slope Armor + #loc_BDArmory_part_BD2x1slopeArmor_title = BD 2x1斜面装甲 + //A sturdy 2x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD2x1slopeArmor_description = 一块结实的2x1斜面装甲板,适用于建造各种产品。注:并不能漂浮。 + + //BD 1x1 panel Armor + #loc_BDArmory_part_BD1x1panelArmor_title = BD 1x1装甲板 + //A sturdy 1x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD1x1panelArmor_description = 一块结实的1x1装甲板,适用于建造各种产品。注:并不能漂浮。 + + //BD 2x1 panel Armor + #loc_BDArmory_part_BD2x1panelArmor_title = BD 2x1装甲板 + //A sturdy 2x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD2x1panelArmor_description = 一块结实的2x1装甲板,适用于建造各种产品。注:并不能漂浮。 + + //BD 3x1 panel Armor + #loc_BDArmory_part_BD3x1panelArmor_title = BD 3x1装甲板 + //A sturdy 3x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD3x1panelArmor_description = 一块结实的3x1装甲板,适用于建造各种产品。注:并不能漂浮。 + + //BD 4x1 panel Armor + #loc_BDArmory_part_BD4x1panelArmor_title = BD 4x1装甲板 + //A sturdy 4x1 Armor plate, perfect for constructing all sorts of things. PS does not float + #loc_BDArmory_part_BD4x1panelArmor_description = 一块结实的4x1装甲板,适用于建造各种产品。注:并不能漂浮。 + + //AWACS Detection Radar + #loc_BDArmory_part_awacsRadar_title = 空中预警系统探测雷达 + //A large radar capable of detecting objects from a long distance. This radar does NOT have the capability of tracking or locking targets. + #loc_BDArmory_part_awacsRadar_description = 一款能探测远距离目标的大型雷达。该雷达没有追踪或锁定目标的能力。 + + //Modular Missile Guidance (EXPERIMENTAL) + #loc_BDArmory_part_bdammGuidanceModule_title = 导弹引导模块(实验功能) + //A missile guidance computer. Manually tune steering settings to craft's unique flight characteristics. Select a guidance mode. Select a target then enable guidance. Activate engines and stages manually. (EXPERIMENTAL) + #loc_BDArmory_part_bdammGuidanceModule_description = 一台导弹制导计算机。请根据你的导弹实际性能调节各项飞行参数,设置制导模式,锁定目标启用制导,手动控制启动引擎和分级顺序即可。(实验功能) + + //Browning .50cal AN/M2 + #loc_BDArmory_part_bahaBrowningAnm2_title = 勃朗宁.50口径AN/M3机枪 + //An old fixed .50 cal machine gun 50cal ammo + #loc_BDArmory_part_bahaBrowningAnm2_description = 旧式.50口径固定机枪。 + + //CBU-87 Cluster Bomb + #loc_BDArmory_part_bahaClusterBomb_title = CBU-87集束炸弹 + //This bomb splits open and deploys many small bomblets at a certain altitude. + #loc_BDArmory_part_bahaClusterBomb_description = 该炸弹会在预设高度炸开并投放大量子弹药。 + + //Chaff Dispenser + #loc_BDArmory_part_bahaChaffPod_title = 箔条发射器 + //Drops chaff for confusing or breaking radar locks. + #loc_BDArmory_part_bahaChaffPod_description = 能投放用于迷惑和解除雷达锁定的干扰箔条。 + + //Flare Dispenser + #loc_BDArmory_part_bahaCmPod_title = 热诱弹发射器 + //Drops flares for confusing heat-seeking missiles. + #loc_BDArmory_part_bahaCmPod_description = 能投放用于迷惑红外制导导弹的热诱弹。 + + //AN/ALQ-131 ECM Jammer + #loc_BDArmory_part_bahaECMJammer_title = AN/ALQ-131电子反制装置 + //This electronic device makes it harder for radars to lock onto your vehicle, and increases your chances of breaking the lock. + #loc_BDArmory_part_bahaECMJammer_description = 该电子设备可以使雷达更难以锁定你的载具,并增大机动脱锁概率。 + + //GAU-8 30x173mm Cannon + #loc_BDArmory_part_bahaGau-8_title = GAU-8 30x173mm机炮 + //A 7 barrel 30mm rotary cannon. + #loc_BDArmory_part_bahaGau-8_description = 7管30mm转管机炮。 + + //Goalkeeper CIWS + #loc_BDArmory_part_bahaGoalKeeper_title = “守门员”近防系统 + #loc_BDArmory_part_bahaGoalKeeper_description = 可以全向旋转的7管30mm转管机炮炮塔。30mm的高爆弹药会在预设距离上爆炸,但该武器并没有自动设置定时引信的功能。其自带的探测和追踪雷达只在短距离上有效,不能用来取代大型探测雷达。 + + //GoalkeeperMk1 CIWS + #loc_BDArmory_part_GoalKeeperBDAcMk1_title = “守门员”Mk 1近防系统 + #loc_BDArmory_part_GoalKeeperBDAcMk1_description = 可以全向旋转的7管30mm转管机炮炮塔。Mk 1版本是从一大片泥地里的一块帐篷布底下发现的,因为价格便宜,特别适合预算有限的军事组织和政府采购。该版本没有探测和追踪用的雷达,需要第三方提供目标信息(让人去观察和指示目标不太好使,因为这玩意发射时的噪音实在是有点大)。其发射的30mm的高爆弹药等飞累了就会自行爆炸,该武器并没有自动设置定时引信的功能。 + + //Goalkeeper MK2 CIWS + #loc_BDArmory_part_BDAcGKmk2_title = “守门员”Mk 2近防系统 + #loc_BDArmory_part_BDAcGKmk2_description = 可以全向旋转的7管30mm转管机炮炮塔。Mk 2版本则是在旧KSC的机库里面,从一大堆空喷漆罐子下面挖出来的,其开发思路基于Mk 1,核心思想是减轻早期观测手受到的听力减退困扰。Mk 2比起Mk 1来说有几项优势,其装备了红外瞄准系统和雷达信号接收机。其发射的30mm的高爆弹药只比Mk 1的稍微改进了一点,飞累了自行爆炸所需的时间要稍微长一些,这样击中目标的概率就大了一点,但是该武器自始至终也还是没有自动设置定时引信的功能。 + + //TWS Locking Radar + #loc_BDArmory_part_scanLockRadar1_title = 边扫描边跟踪雷达 + #loc_BDArmory_part_scanLockRadar1_description = 该设备由一台中距探测雷达与一台内建的追踪雷达组成。该雷达可以锁定目标,且在追踪已锁定目标的同时还可以继续扫描(即TWS - Track While Scan)。适用于防空搜索与追踪,但并不适合探测和追踪地面目标。 + + //Large Detection Radar + #loc_BDArmory_part_scanLargeRadar_title = 大型探测雷达 + #loc_BDArmory_part_scanLargeRadar_description = 具有长距离发现目标能力的大型雷达。该雷达无法追踪和锁定目标,适用于防空警戒,难以探测地面目标。 + + //Hydra-70 Rocket Pod + #loc_BDArmory_part_bahaH70Launcher_title = 火蛇70火箭弹发射器 + //Holds and fires 19 unguided Hydra-70 rockets. + #loc_BDArmory_part_bahaH70Launcher_description = 内装19枚火蛇70火箭弹的发射器。 + + //Hydra-70 Rocket Turret + #loc_BDArmory_part_bahaH70Turret_title = 火蛇70火箭弹炮塔 + //Turret pod that holds and fires 32 unguided Hydra-70 rockets. + #loc_BDArmory_part_bahaH70Turret_description = 内装32枚火蛇70火箭弹的旋转发射器炮塔。 + + //AGM-88 HARM Missile + #loc_BDArmory_part_bahaHarm_title = AGM-88高速反辐射(HARM)导弹 + //High-speed anti-radiation missile. This missile will home in on radar sources detected by the Radar Warning Receiver. + #loc_BDArmory_part_bahaHarm_description = 高速反辐射导弹。该导弹会自动追踪攻击由雷达警告接收器发现的雷达信号源。 + + //HE-KV-1 Missile + #loc_BDArmory_part_bahaHEKV1_title = HE-KV-1导弹 + //The HE-KV-1 (High explosive kill vehicle) is a radar-guided homing missile that uses reaction control thrusters and thrust vectoring to maneuver. This means it is capable of steering towards targets in a vacuum. + #loc_BDArmory_part_bahaHEKV1_description = HE-KV-1(High explosive kill vehicle,高爆攻击弹药)是一款使用RCS和推力矢量控制机动的雷达制导导弹,也就是说其可以在真空中转向攻击目标。 + + //AGM-114 Hellfire Missile + #loc_BDArmory_part_bahaAGM-114_title = AGM-114“地狱火”导弹 + //Small, quick, laser guided homing missile. + #loc_BDArmory_part_bahaAGM-114_description = 小型高速激光制导导弹。 + + //Vulcan (Hidden) + #loc_BDArmory_part_bahaHiddenVulcan_title = “火神”机炮(隐身型) + //A 6 barrel 20x102mm rotary cannon. 20x102Ammo + #loc_BDArmory_part_bahaHiddenVulcan_description = 六管20x102mm转管机炮。(发射20x102Ammo) + + //Mk83 JDAM Bomb + #loc_BDArmory_part_bahaJdamMk83_title = Mk 83联合直接攻击弹药 + //1000lb GPS-guided bomb. + #loc_BDArmory_part_bahaJdamMk83_description = 1000磅GPS制导炸弹。 + + //M102 Howitzer (Radial) + #loc_BDArmory_part_bahaM102Howitzer_title = M102榴弹炮(侧面安装版) + //A radially mounted 105mm gun. CannonShells + #loc_BDArmory_part_bahaM102Howitzer_description = 105mm侧面安装火炮。(发射CannonShells) + + //M1 Abrams Cannon + #loc_BDArmory_part_bahaM1Abrams_title = M1“艾布拉姆斯”主炮 + //A 120mm cannon on an armored turret. CannonShells + #loc_BDArmory_part_bahaM1Abrams_description = 安装在装甲炮塔上的120mm火炮。(发射CannonShells) + + //M230 Chain Gun Turret + #loc_BDArmory_part_bahaM230ChainGun_title = M230弹链供弹机炮 + //The M230 Chain Gun is a single-barrel automatic cannon firing 30x173 Ammo high explosive rounds. It is commonly used on attack helicopters. + #loc_BDArmory_part_bahaM230ChainGun_description = M230弹链供弹机炮是一款发射30x173mm高爆弹药的单管自动武器,常安装于武装直升机上。 + + //AGM-65 Maverick Missile + #loc_BDArmory_part_bahaAGM-65_title = AGM-65“小牛”导弹 + //Medium yield laser guided air-to-ground missile. + #loc_BDArmory_part_bahaAGM-65_description = 中等当量激光制导空对地导弹。 + + //Jernas Missile Turret + #loc_BDArmory_part_missileTurretTest_title = “贾纳斯”旋转导弹架 + //A turret capable of holding and firing up to 8 small to medium sized missiles. Comes with an integrated detection and tracking radar. Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_missileTurretTest_description = 可以安装并发射最多8枚小型至中型导弹的导弹架,内置探测追踪雷达。如果上面安装了不是导弹的任何东西则保修失效。在武器管理器里选择所安装的导弹即可启动导弹架。 + + //Mk82 Bomb + #loc_BDArmory_part_bahaMk82Bomb_title = Mk 82炸弹 + //500lb unguided bomb. + #loc_BDArmory_part_bahaMk82Bomb_description = 500磅无制导炸弹。 + + //Mk82 SnakeEye Bomb + #loc_BDArmory_part_bahaMk82BombBrake_title = Mk 82“蛇眼”炸弹 + //500lb unguided bomb with airbrakes. Use for low altitude bombing. + #loc_BDArmory_part_bahaMk82BombBrake_description = 带减速板的500磅无制导炸弹,用于低高度轰炸。 + + //Oerlikon Millennium Cannon + #loc_BDArmory_part_bahaOMillennium_title = 厄利孔“千禧年”机炮 + //A turret that fires timed detonation explosive rounds. Suited for close-in air defense. A device at the muzzle end of the barrel measures the exact speed of each round as it is fired, and automatically sets the fuse to detonate the round as it approaches a pre-set distance from the target. Uses 30x173Ammo + #loc_BDArmory_part_bahaOMillennium_description = 发射定时爆炸高爆弹的炮塔,适合短距离防空任务。炮口处有测量每发炮弹初速度、并自动校准引信的装置,使炮弹能准确地在抵近目标的预设距离上爆炸。(发射30x173Ammo) + + //PAC-3 Intercept Missile + #loc_BDArmory_part_bahaPac-3_title = PAC-3“爱国者”拦截导弹 + //Medium range, high speed, radar-guided surface to air missile. + #loc_BDArmory_part_bahaPac-3_description = 中距高速雷达制导地对空导弹。 + + //Patriot Launcher Turret + #loc_BDArmory_part_patriotLauncherTurret_title = “爱国者”导弹发射器 + //A turret capable of holding and firing up to 16 PAC-3 missiles (4 per cannister). Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_patriotLauncherTurret_description = 可以安装并发射最多16枚(每个隔间4枚)PAC-3导弹的导弹发射器。如果上面安装了不是导弹的任何东西则保修失效。在武器管理器里选择所安装的导弹即可启动发射器。 + + //Radar Data Receiver + #loc_BDArmory_part_radarDataReceiver_title = 雷达数据接收器 + //A module that can display radar contacts via data-link and lock targets through a remote radar, but can not scan or lock by itself. Useful for a hidden missile battery. + #loc_BDArmory_part_radarDataReceiver_description = 该模块可以经由数据链接收雷达信息,并通过链接的其他雷达锁定目标,但是不能自行扫描或锁定目标。适合用于隐蔽的导弹炮台等单位。 + + //AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1_title = AN/APG-63机头雷达 + #loc_BDArmory_part_bdRadome1_description = 带气动保护罩的前视雷达,可以在120度视场内扫描并锁定目标。其专为空战优化,难以锁定地面目标。 + + //AN/APG-63 Inline Radome + #loc_BDArmory_part_bdRadome1inline_title = AN/APG-63内置型机载雷达 + //A forward facing, aerodynamically housed radar. It can scan and lock targets within a 120 degree field of view. Make sure the black markings are pointing forward. It is optimized for air-to-air combat, and has difficulties locking surface targets. + #loc_BDArmory_part_bdRadome1inline_description = 带气动保护罩的前视雷达,可以在120度视场内扫描并锁定目标。安装时请注意黑色箭头务必指向前方,其专为空战优化,难以锁定地面目标。 + + //AN/APG-63 Radome + #loc_BDArmory_part_bdRadome1snub_title = AN/APG-63对地型机头雷达 + #loc_BDArmory_part_bdRadome1snub_description = 带气动保护罩的前视雷达,可以在120度视场内扫描并锁定目标。该型号为对地攻击做了特别优化,攻击地面目标效能大大增强,但其对空作战能力因此受限。 + + //RBS-15 Cruise Missile + #loc_BDArmory_part_bahaRBS-15Cruise_title = RBS-15巡航导弹 + //Long distance, multi-platform high-speed cruise missile with boosters. + #loc_BDArmory_part_bahaRBS-15Cruise_description = 长距多平台高速巡航导弹,附带助推器。 + + //Adjustable Rotary Bomb Rack + #loc_BDArmory_part_bdRotBombBay_title = 可调旋转弹架 + //An adjustable rotary bomb rack. The yellow arrow should be pointing in the direction of weapon release. Missiles or bombs only. One per rail only. + #loc_BDArmory_part_bdRotBombBay_description = 可调节的旋转弹架。黄色箭头指向武器投放方向,仅限安装导弹和炸弹,一根支架限一枚。 + + //S-8KOM Rocket Pod + #loc_BDArmory_part_bahaS-8Launcher_title = S-8KOM火箭弹发射器 + //Holds and fires 23 unguided S-8KOM rockets. It has an aerodynamic nose cone. + #loc_BDArmory_part_bahaS-8Launcher_description = 内装23枚S-8KOM无制导火箭弹的发射器,附带气动头锥。 + + //AIM-9 Sidewinder Missile + #loc_BDArmory_part_bahaAim9_title = AIM-9“响尾蛇”导弹 + //Short range heat seeking missile. + #loc_BDArmory_part_bahaAim9_description = 短距红外制导导弹。 + + //Small High Explosive Warhead + #loc_BDArmory_part_bdWarheadSmall_title = 小型高爆弹头 + //A missile nose cone packed with explosives. + #loc_BDArmory_part_bdWarheadSmall_description = 一个内含炸药的导弹头锥。 + + //Smoke Countermeasure Pod + #loc_BDArmory_part_bahaSmokeCmPod_title = 防御烟雾发生器 + //Fires smoke-screen countermeasures for occluding laser points. + #loc_BDArmory_part_bahaSmokeCmPod_description = 可发射用于遮蔽激光瞄准系统视野的防御烟幕。 + + //FLIR Targeting Ball + #loc_BDArmory_part_bahaFlirBall_title = FLIR球形瞄准摄像头 + //A ball camera used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + #loc_BDArmory_part_bahaFlirBall_description = 用于瞄准和侦察目标的球形摄像头。带有高清摄像头和垂直稳定系统,可感知红外线,使你能迅速发现和锁定供导弹攻击的地面目标。 + + //AN/AAQ-28 Targeting Pod + #loc_BDArmory_part_bahaCamPod_title = AN/AAQ-28瞄准吊舱 + //A targeting pod used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. + #loc_BDArmory_part_bahaCamPod_description = 用于瞄准和侦察目标的吊舱。带有高清摄像头和垂直稳定系统,可感知红外线,使你能迅速发现和锁定供导弹攻击的地面目标。 + + //Tow Launcher + #loc_BDArmory_part_towLauncherTurret_title = “陶”式发射器 + //A turret capable of holding and firing up to 4 TOW missiles. Warranty void if anything except TOW missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + #loc_BDArmory_part_towLauncherTurret_description = 能安装并发射最多4枚“陶”式导弹的旋转发射器。如果安装了除“陶”式以外的其他导弹则保修失效。在武器管理器里选择所安装的导弹即可启动发射器。 + + //BGM-71 Tow Missile + #loc_BDArmory_part_bahaTowMissile_title = BGM-71“陶”式反坦克导弹 + //Short distance, laser beam-riding, wireless anti-tank missile. + #loc_BDArmory_part_bahaTowMissile_description = 短程无线激光驾束制导反坦克导弹。 + + //Weapon Manager + #loc_BDArmory_part_missileController_title = 武器管理器 + //Cycle through missiles/bombs and fire them with a single button. + #loc_BDArmory_part_missileController_description = 一键管理切换各种武器和发射功能。 + + //BDAsonarPod1A + #loc_BDArmory_part_BDAsonarPod1A_title = BDA Mk 1声纳吊舱 + //BDA MK1 Sonar Pod can only detect splashed and submerged vessels mount below waterline for best results. As a hull-mounted sonar it has limited range and sensitivity only. + #loc_BDArmory_part_BDAsonarPod1A_description = BDA Mk 1声纳吊舱适合完全浸没在水下工作,可以用于探测水面和潜水的目标。如果装在水面以上的部分,其探测距离和灵敏度将大打折扣。 + + //StingRayBDATorpedo + #loc_BDArmory_part_StingRayBDATorpedo_title = “魟鱼”BDA轻型鱼雷 + //Sting Ray Light Weight Torpedo Ship launch, and heli launch airdrop do not use in submarines. Interesting fact, you can fit 16 of these in a pac launcher, though using them in such a device without proper training has been the cause of much weeping and letters written. + #loc_BDArmory_part_StingRayBDATorpedo_description = “魟鱼”轻型鱼雷由舰船和直升机发射,请勿用作潜艇鱼雷。顺便有个好玩的事,你可以在“爱国者”发射器里面塞进16枚鱼雷,但是这样非常危险,未经训练进行操作可能导致你事后得哭着写上万字的检讨。 + + //SaturnAL31 + #loc_BDArmory_part_SaturnAL31_title = Saturn AL-31FM1 Afterburning Jet Engine + //A high performance jet engine with a variable geometry thrust vectoring nozzle and an afterburner for extra thrust. Based on the highly popular J-404 engine, KTech engineers saw the potential of (highly) modifying the commercial variant into a formidable powerplant for military use. After seeing the potential of the engine, the BDAc group immediately licensed it for their new MkIII test drone. + #loc_BDArmory_part_SaturnAL31_description = 高性能喷气发动机,带有可变几何形状的推力矢量喷嘴和用于额外推力的加力燃烧室。 基于备受欢迎的J-404发动机,KTech工程师看到了(高度)将商用变型改造成军事用途的强大动力装置的潜力。 在看到发动机的潜力后,BDAc集团立即将其用于新的MkIII测试无人机。 + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Localization/part_deformatter.cfg b/BDArmory/Distribution/GameData/BDArmory/Localization/part_deformatter.cfg new file mode 100644 index 000000000..06a7bd79f --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Localization/part_deformatter.cfg @@ -0,0 +1,517 @@ +//Replacing all title/manufacturers/descriptions with localization tags +@PART[bahaGatlingGun]:FINAL +{ + @title = #loc_BDArmory_part_bahaGatlingGun_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaGatlingGun_description +} + + +@PART[bahaTurret]:FINAL +{ + @title = #loc_BDArmory_part_bahaTurret_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaTurret_description +} + + +@PART[bahaABL]:FINAL +{ + @title = #loc_BDArmory_part_bahaABL_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaABL_description +} + + +@PART[bahaAdjustableRail]:FINAL +{ + @title = #loc_BDArmory_part_bahaAdjustableRail_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaAdjustableRail_description +} + + +@PART[bahaAgm86B]:FINAL +{ + @title = #loc_BDArmory_part_bahaAgm86B_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaAgm86B_description +} + + +@PART[bahaAim120]:FINAL +{ + @title = #loc_BDArmory_part_bahaAim120_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaAim120_description +} + + +@PART[bdPilotAI]:FINAL +{ + @title = #loc_BDArmory_part_bdPilotAI_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bdPilotAI_description +} + + +@PART[baha20mmAmmo]:FINAL +{ + @title = #loc_BDArmory_part_baha20mmAmmo_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_baha20mmAmmo_description +} + + +@PART[baha30mmAmmo]:FINAL +{ + @title = #loc_BDArmory_part_baha30mmAmmo_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_baha30mmAmmo_description +} + + +@PART[baha50CalAmmo]:FINAL +{ + @title = #loc_BDArmory_part_baha50CalAmmo_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_baha50CalAmmo_description +} + + +@PART[UniversalAmmoBoxBDA]:FINAL +{ + @title = #loc_BDArmory_part_UniversalAmmoBoxBDA_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_UniversalAmmoBoxBDA_description +} + + +@PART[bahaCannonShellBox]:FINAL +{ + @title = #loc_BDArmory_part_bahaCannonShellBox_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaCannonShellBox_description +} + + +@PART[BD1x1slopeArmor]:FINAL +{ + @title = #loc_BDArmory_part_BD1x1slopeArmor_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BD1x1slopeArmor_description +} + + +@PART[BD2x1slopeArmor]:FINAL +{ + @title = #loc_BDArmory_part_BD2x1slopeArmor_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BD2x1slopeArmor_description +} + + +@PART[BD1x1panelArmor]:FINAL +{ + @title = #loc_BDArmory_part_BD1x1panelArmor_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BD1x1panelArmor_description +} + + +@PART[BD2x1panelArmor]:FINAL +{ + @title = #loc_BDArmory_part_BD2x1panelArmor_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BD2x1panelArmor_description +} + + +@PART[BD3x1panelArmor]:FINAL +{ + @title = #loc_BDArmory_part_BD3x1panelArmor_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BD3x1panelArmor_description +} + + +@PART[BD4x1panelArmor]:FINAL +{ + @title = #loc_BDArmory_part_BD4x1panelArmor_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BD4x1panelArmor_description +} + + +@PART[awacsRadar]:FINAL +{ + @title = #loc_BDArmory_part_awacsRadar_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_awacsRadar_description +} + + +@PART[bdammGuidanceModule]:FINAL +{ + @title = #loc_BDArmory_part_bdammGuidanceModule_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bdammGuidanceModule_description +} + + +@PART[bahaBrowningAnm2]:FINAL +{ + @title = #loc_BDArmory_part_bahaBrowningAnm2_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaBrowningAnm2_description +} + + +@PART[bahaClusterBomb]:FINAL +{ + @title = #loc_BDArmory_part_bahaClusterBomb_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaClusterBomb_description +} + + +@PART[bahaChaffPod]:FINAL +{ + @title = #loc_BDArmory_part_bahaChaffPod_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaChaffPod_description +} + + +@PART[bahaCmPod]:FINAL +{ + @title = #loc_BDArmory_part_bahaCmPod_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaCmPod_description +} + + +@PART[bahaECMJammer]:FINAL +{ + @title = #loc_BDArmory_part_bahaECMJammer_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaECMJammer_description +} + + +@PART[bahaGau-8]:FINAL +{ + @title = #loc_BDArmory_part_bahaGau-8_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaGau-8_description +} + + +@PART[bahaGoalKeeper]:FINAL +{ + @title = #loc_BDArmory_part_bahaGoalKeeper_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaGoalKeeper_description +} + + +@PART[GoalKeeperBDAcMk1]:FINAL +{ + @title = #loc_BDArmory_part_GoalKeeperBDAcMk1_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_GoalKeeperBDAcMk1_description +} + + +@PART[BDAcGKmk2]:FINAL +{ + @title = #loc_BDArmory_part_BDAcGKmk2_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BDAcGKmk2_description +} + + +@PART[scanLockRadar1]:FINAL +{ + @title = #loc_BDArmory_part_scanLockRadar1_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_scanLockRadar1_description +} + + +@PART[scanLargeRadar]:FINAL +{ + @title = #loc_BDArmory_part_scanLargeRadar_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_scanLargeRadar_description +} + + +@PART[bahaH70Launcher]:FINAL +{ + @title = #loc_BDArmory_part_bahaH70Launcher_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaH70Launcher_description +} + + +@PART[bahaH70Turret]:FINAL +{ + @title = #loc_BDArmory_part_bahaH70Turret_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaH70Turret_description +} + + +@PART[bahaHarm]:FINAL +{ + @title = #loc_BDArmory_part_bahaHarm_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaHarm_description +} + + +@PART[bahaHEKV1]:FINAL +{ + @title = #loc_BDArmory_part_bahaHEKV1_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaHEKV1_description +} + + +@PART[bahaAGM-114]:FINAL +{ + @title = #loc_BDArmory_part_bahaAGM-114_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaAGM-114_description +} + + +@PART[bahaHiddenVulcan]:FINAL +{ + @title = #loc_BDArmory_part_bahaHiddenVulcan_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaHiddenVulcan_description +} + + +@PART[bahaJdamMk83]:FINAL +{ + @title = #loc_BDArmory_part_bahaJdamMk83_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaJdamMk83_description +} + + +@PART[bahaM102Howitzer]:FINAL +{ + @title = #loc_BDArmory_part_bahaM102Howitzer_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaM102Howitzer_description +} + + +@PART[bahaM1Abrams]:FINAL +{ + @title = #loc_BDArmory_part_bahaM1Abrams_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaM1Abrams_description +} + + +@PART[bahaM230ChainGun]:FINAL +{ + @title = #loc_BDArmory_part_bahaM230ChainGun_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaM230ChainGun_description +} + + +@PART[bahaAGM-65]:FINAL +{ + @title = #loc_BDArmory_part_bahaAGM-65_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaAGM-65_description +} + + +@PART[missileTurretTest]:FINAL +{ + @title = #loc_BDArmory_part_missileTurretTest_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_missileTurretTest_description +} + + +@PART[bahaMk82Bomb]:FINAL +{ + @title = #loc_BDArmory_part_bahaMk82Bomb_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaMk82Bomb_description +} + + +@PART[bahaMk82BombBrake]:FINAL +{ + @title = #loc_BDArmory_part_bahaMk82BombBrake_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaMk82BombBrake_description +} + + +@PART[bahaOMillennium]:FINAL +{ + @title = #loc_BDArmory_part_bahaOMillennium_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaOMillennium_description +} + + +@PART[bahaPac-3]:FINAL +{ + @title = #loc_BDArmory_part_bahaPac-3_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaPac-3_description +} + + +@PART[patriotLauncherTurret]:FINAL +{ + @title = #loc_BDArmory_part_patriotLauncherTurret_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_patriotLauncherTurret_description +} + + +@PART[radarDataReceiver]:FINAL +{ + @title = #loc_BDArmory_part_radarDataReceiver_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_radarDataReceiver_description +} + + +@PART[bdRadome1]:FINAL +{ + @title = #loc_BDArmory_part_bdRadome1_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bdRadome1_description +} + + +@PART[bdRadome1inline]:FINAL +{ + @title = #loc_BDArmory_part_bdRadome1inline_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bdRadome1inline_description +} + + +@PART[bdRadome1snub]:FINAL +{ + @title = #loc_BDArmory_part_bdRadome1snub_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bdRadome1snub_description +} + + +@PART[bahaRBS-15Cruise]:FINAL +{ + @title = #loc_BDArmory_part_bahaRBS-15Cruise_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaRBS-15Cruise_description +} + + +@PART[bdRotBombBay]:FINAL +{ + @title = #loc_BDArmory_part_bdRotBombBay_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bdRotBombBay_description +} + + +@PART[bahaS-8Launcher]:FINAL +{ + @title = #loc_BDArmory_part_bahaS-8Launcher_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaS-8Launcher_description +} + + +@PART[bahaAim9]:FINAL +{ + @title = #loc_BDArmory_part_bahaAim9_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaAim9_description +} + + +@PART[bdWarheadSmall]:FINAL +{ + @title = #loc_BDArmory_part_bdWarheadSmall_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bdWarheadSmall_description +} + + +@PART[bahaSmokeCmPod]:FINAL +{ + @title = #loc_BDArmory_part_bahaSmokeCmPod_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaSmokeCmPod_description +} + + +@PART[bahaFlirBall]:FINAL +{ + @title = #loc_BDArmory_part_bahaFlirBall_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaFlirBall_description +} + + +@PART[bahaCamPod]:FINAL +{ + @title = #loc_BDArmory_part_bahaCamPod_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaCamPod_description +} + + +@PART[towLauncherTurret]:FINAL +{ + @title = #loc_BDArmory_part_towLauncherTurret_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_towLauncherTurret_description +} + + +@PART[bahaTowMissile]:FINAL +{ + @title = #loc_BDArmory_part_bahaTowMissile_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_bahaTowMissile_description +} + + +@PART[missileController]:FINAL +{ + @title = #loc_BDArmory_part_missileController_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_missileController_description +} + +@PART[BDAsonarPod1A]:FINAL +{ + @title = #loc_BDArmory_part_BDAsonarPod1A_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_BDAsonarPod1A_description +} + +@PART[StingRayBDATorpedo]:FINAL +{ + @title = #loc_BDArmory_part_StingRayBDATorpedo_title + @manufacturer = #loc_BDArmory_part_manufacturer + @description = #loc_BDArmory_part_StingRayBDATorpedo_description +} diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/000000_HitpointModule.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/000000_HitpointModule.cfg new file mode 100644 index 000000000..cc5eef90b --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/000000_HitpointModule.cfg @@ -0,0 +1,25 @@ +//Do not apply this module with options, thus commented out. +//Create seperate MM patches to override calculated values from code + +@PART[*] +{ + %MODULE[HitpointTracker] + { + //HitPoints = 0 + //maxHitPoints = 0 + //Armor = 0 + //ArmorThickness = 0 + //ExplodeMode = Never + } +} + +@PART[kerbalEVA*] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 5 + maxHitPoints = 500 + ExplodeMode = Never + } + +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/000000_HitpointModule_PartFixes.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/000000_HitpointModule_PartFixes.cfg new file mode 100644 index 000000000..6952397eb --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/000000_HitpointModule_PartFixes.cfg @@ -0,0 +1,92 @@ +/////////////////////////////////////////// +//Fixes for Mass/Density anomoalies in KSP +/////////////////////////////////////////// + +@PART[turboJet] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 2000 + ExplodeMode = Never + } + +} + +@PART[elevon*] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 500 + ExplodeMode = Never + } + +} + + +@PART[B9.Aero.Wing.Procedural.TypeB] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 500 + ExplodeMode = Never + } + +} + +@PART[winglet3] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 650 + ExplodeMode = Never + } + +} + +@PART[tailfin] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 750 + ExplodeMode = Never + } + +} + +@PART[AdvancedCanard] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 750 + ExplodeMode = Never + } + +} + +@PART[CanardController] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 750 + ExplodeMode = Never + } + +} + +@PART[nacelleBody] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 750 + ExplodeMode = Never + } + +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/10_bdac_stealth.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/10_bdac_stealth.cfg new file mode 100644 index 000000000..f4ef900e0 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/10_bdac_stealth.cfg @@ -0,0 +1,37 @@ +// Use the new radar & jamming system to apply +// "stealth" / "radar absorbent material" +// to the BDA F22 Raptor cockpit. +// This work by defining it as an always-on +// ECM-jammer with rcs reduction effect, but no +// lock breaking or detection increase effect. +// Radar cross ection (RCS) will be reduced as +// a factor to the whole craft! + + +@PART[bahaMk22LightningCockpit] +{ + @description = This is a two-man fighter cockpit with a Mk2 cross section. Inspired by the F-22, the module has built-in air intakes, a fully loaded IVA and a huge glass canopy. You'll be able to clearly see all around you. Just hope it can withstand the vacuum of space. Accessible through the MFDs are several external cameras. This cockpit is coated with radar absorbent material (RAM) and significantly reduces the radar cross section of the plane. + @cost = 10500 // yeah, stealth coating is expensive! + @maxTemp = 1000 //stealth coating is fragile, hence values lowered! + @skinMaxTemp = 1500 //stealth coating is fragile, hence values lowered! + + MODULE + { + name = ModuleECMJammer + + // Jammer capabilities: + alwaysOn = true // can be enabled/disabled, or is always on + // Set this to true for "stealth" jammers that are integrated into Cockpits and serve + // to reduce only the radar cross section, but without providing another jamming effect! + + resourceDrain = 0 // EC/sec. Set this higher for more capabale jammers. + + jammerStrength = 0 // this is a factor (in relation to a vessels base radar cross section) how much the crafts DETECTABILITY is INCREASED(!) when the jammer is active + + lockBreaker = false // true: jammer serves to break radar locks (default: true) + lockBreakerStrength = 0 // factor (in relation to a vessels base radar cross section) how strong the lockbreaking effect is + + rcsReduction = true // jammer reduces a crafts radar cross section, simulating 2nd generation stealth (radar obsorbent coating) + rcsReductionFactor = 0.65 // factor for radar cross section: from 0 (craft is invisible) to 1 (no effect) + } +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/Armor_CVE.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/Armor_CVE.cfg new file mode 100644 index 000000000..37a11cace --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/Armor_CVE.cfg @@ -0,0 +1,32 @@ +@PART[EHInimitzRadar] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 50 + maxHitPoints = 8000 + ExplodeMode = Never + } + +} + +@PART[EHInimitz] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 300000 + ExplodeMode = Never + } + +} + +@PART[ehiNimitzBridge] +{ + %MODULE[HitpointTracker] + { + ArmorThickness = 10 + maxHitPoints = 100000 + ExplodeMode = Never + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_Armor.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_Armor.cfg new file mode 100644 index 000000000..6093d2004 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_Armor.cfg @@ -0,0 +1,17 @@ +@PART[BD*Armor] +{ + %MODULE[HitpointTracker] + { + maxHitPoints = 8000 + ArmorThickness = 150 + } +} + +@PART[BD*Armor]:NEEDS[TweakScale] +{ + MODULE + { + name = TweakScale + type = free_square + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_GroundRadar.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_GroundRadar.cfg new file mode 100644 index 000000000..2ff0431b8 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_GroundRadar.cfg @@ -0,0 +1,107 @@ ++PART[bdRadome1snub] +{ + @name = bdRadome1snubGA + @title = APG-77v1 air-to-ground Radar (Snub) + @description = The AN/APG-77v1 is a forward facing, aerodynamically housed, solid-state, active electronically scanned array (AESA) radar. It provides full air-to-ground functionality at a MAX operating range of 40km against stationary and moving targets within a 120 degree field of view. This particular unit is optimized for Ground combat, and has difficulties locking air targets. + @MODULE[ModuleRadar] + { + @radarGroundClutterFactor = 1.7 + @radarName = APG-77 atg + @radarDetectionCurve + { + key = 0 0 0 0 + key = 5 0.9 0.29 0.31 + key = 10 3 0.48 0.51 + key = 15 5.9 0.62 0.69 + key = 20 10 0.96 0.9 + key = 25 14.1 0.71 0.71 + key = 30 17.3 0.58 0.58 + key = 35 20 0.48 0.61 + key = 40 35 9.18 1.5 + } + @radarLockTrackCurve + { + key = 0 0 0 0 + key = 5 0.9 0.47 0.44 + key = 10 3.5 0.59 0.59 + key = 15 7 0.73 0.71 + key = 20 11 0.79 0.9 + key = 25 16 1.05 1.05 + key = 30 21 1.09 0.9 + key = 35 25 0.48 0.49 + key = 40 40 9.18 1.5 + } + } +} + ++PART[bdRadome1inline] +{ + @name = bdRadome1inlineGA + @title = APG-77v1 air-to-ground Radar (Inline) + @description = The AN/APG-77v1 is a forward facing, aerodynamically housed, solid-state, active electronically scanned array (AESA) radar. It provides full air-to-ground functionality at a MAX operating range of 40km against stationary and moving targets within a 120 degree field of view. This particular unit is optimized for Ground combat, and has difficulties locking air targets. + @MODULE[ModuleRadar] + { + @radarGroundClutterFactor = 1.7 + @radarName = APG-77 atg + @radarDetectionCurve + { + key = 0 0 0 0 + key = 5 0.9 0.29 0.31 + key = 10 3 0.48 0.51 + key = 15 5.9 0.62 0.69 + key = 20 10 0.96 0.9 + key = 25 14.1 0.71 0.71 + key = 30 17.3 0.58 0.58 + key = 35 20 0.48 0.61 + key = 40 35 9.18 1.5 + } + @radarLockTrackCurve + { + key = 0 0 0 0 + key = 5 0.9 0.47 0.44 + key = 10 3.5 0.59 0.59 + key = 15 7 0.73 0.71 + key = 20 11 0.79 0.9 + key = 25 16 1.05 1.05 + key = 30 21 1.09 0.9 + key = 35 25 0.48 0.49 + key = 40 40 9.18 1.5 + } + } +} + ++PART[bdRadome1] +{ + @name = bdRadome1GA + @title = APG-77v1 air-to-ground Radar + @description = The AN/APG-77v1 is a forward facing, aerodynamically housed, solid-state, active electronically scanned array (AESA) radar. It provides full air-to-ground functionality at a MAX operating range of 40km against stationary and moving targets within a 120 degree field of view. This particular unit is optimized for Ground combat, and has difficulties locking air targets. + @MODULE[ModuleRadar] + { + @radarGroundClutterFactor = 1.7 + @radarName = APG-77 atg + @radarDetectionCurve + { + key = 0 0 0 0 + key = 5 0.9 0.29 0.31 + key = 10 3 0.48 0.51 + key = 15 5.9 0.62 0.69 + key = 20 10 0.96 0.9 + key = 25 14.1 0.71 0.71 + key = 30 17.3 0.58 0.58 + key = 35 20 0.48 0.61 + key = 40 35 9.18 1.5 + } + @radarLockTrackCurve + { + key = 0 0 0 0 + key = 5 0.9 0.47 0.44 + key = 10 3.5 0.59 0.59 + key = 15 7 0.73 0.71 + key = 20 11 0.79 0.9 + key = 25 16 1.05 1.05 + key = 30 21 1.09 0.9 + key = 35 25 0.48 0.49 + key = 40 40 9.18 1.5 + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_TweakScale.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_TweakScale.cfg new file mode 100644 index 000000000..9df9455de --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/BDA_TweakScale.cfg @@ -0,0 +1,17 @@ +@PART[bdWarheadSmall] +{ + %MODULE[TweakScale] + { + type = stack + defaultScale = 2.5 + } +} + +@PART[awacsRadar] +{ + %MODULE[TweakScale] + { + %name = TweakScale + %type = free + } +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/Explode_Mode_Squad_Tanks.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/Explode_Mode_Squad_Tanks.cfg new file mode 100644 index 000000000..16c022609 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/Explode_Mode_Squad_Tanks.cfg @@ -0,0 +1,302 @@ +// ** Tanks ** + +@PART[fuelTank] // FL-T400 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[fuelTank_long] // FL-T800 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[fuelTank1-2] // Rockomax X200-32 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[fuelTank2-2] // Rockomax X200-16 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[fuelTank3-2] // Rockomax Jumbo-64 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[fuelTank4-2] // Rockomax X200-8 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[fuelTankSmall] // FL-T200 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[fuelTankSmallFlat] // FL-T100 Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[miniFuelTank] // Oscar-B Fuel Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[MK1Fuselage] // Mk1 Fuselage - Jet Fuel +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} +@PART[miniFuselage] // Mk0 Liquid Fuel Fuselage +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +// ========== MK3-Parts ======== +@PART[mk3FuselageLF_25] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk3FuselageLF_50] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk3FuselageMONO] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk3FuselageLFO_25] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk3FuselageLFO_50] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk3FuselageLF_100] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk3FuselageLFO_100] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + + +@PART[adapterMk3-Mk2] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[adapterMk3-Size2] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[adapterMk3-Size2Slant] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[adapterSize3-Mk3] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} +@PART[adapterSize2-Mk2] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} +@PART[adapterSize2-Size1] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} +@PART[adapterSize2-Size1Slant] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} +@PART[adapterEngines] // Mk3 Engine Mount +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[Size3LargeTank] // Kerbodyne S3-14400 Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[Size3MediumTank] // Kerbodyne S3-7200 Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[Size3SmallTank] // Kerbodyne S3-3600 Tank +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + + +@PART[Size3to2Adapter] // Kerbodyne ADTP-2-3 +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} +@PART[mk2_1m_Bicoupler] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk2_1m_AdapterLong] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk2SpacePlaneAdapter] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk2Fuselage] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk2FuselageLongLFO] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk2FuselageShortLiquid] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk2FuselageShortLFO] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} + +@PART[mk2FuselageShortMono] +{ + %MODULE[HitpointTracker] + { + ExplodeMode = Dynamic + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/MMPatches/bdmk22_cockpit.cfg b/BDArmory/Distribution/GameData/BDArmory/MMPatches/bdmk22_cockpit.cfg new file mode 100644 index 000000000..608b4cd6e --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/MMPatches/bdmk22_cockpit.cfg @@ -0,0 +1,56 @@ +// MM-Patch for make existing parts work with the new BDA radar overhaul +// It provides _suggestions_ for how to set the radar's +// detection and locktrack capabilities (floatcurves), as well as the +// look-down effectiveness (ground clutter factor). +// +// THESE PATCHES ARE _NOT_ INTENDED TO BE DISTRIBUTED WITH BDA! +// They are purely for easier testing, and for consideration for +// the original authors when they adapt their part configs to the new +// BDA release. +// You may freely: +// - take this patch and incorporate as-is into your part configs +// - take this patch, use it as a base, change it & distribute it with your parts +// - discard all of this & roll your own, maybe using this change to re-balance +// your parts +// Its all up to you! + +@PART[bahaMk22LightningCockpit] +{ + @MODULE[ModuleRadar] + { + // idea: should feature an integrated radar with somewhat better range + // and sensitivity than the bda stock AN/APG-63V1 + + %radarName = MK22 APG-77 AESA Radar + %resourceDrain = 1.5 + %maxLocks = 5 + radarGroundClutterFactor = 0.15 //optimized for air-2-air combat, terrible look-down performance + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 7 0 //between 0 and 7 km the min cross section is 0, thus assured detection of everything + key = 12 5 // + key = 22 15 // + key = 37 22 + key = 45 35 //maxrange of 45km + } + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + key = 0.0 0 + key = 7 2 //can lock extreme well at close distance + key = 10 5 // + key = 20 15 // + key = 30 25 // + key = 35 35 //can lock only up to 35km, and min rcs is larger than for detection + } + } +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/CMChaff/model.mu b/BDArmory/Distribution/GameData/BDArmory/Models/CMChaff/model.mu new file mode 100644 index 000000000..8af6ac298 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/CMChaff/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/CMChaff/tex_chaffParticle.png b/BDArmory/Distribution/GameData/BDArmory/Models/CMChaff/tex_chaffParticle.png new file mode 100644 index 000000000..c6f094ff2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/CMChaff/tex_chaffParticle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/flareTex.png b/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/flareTex.png new file mode 100644 index 000000000..627a253cb Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/flareTex.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/model.mu b/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/model.mu new file mode 100644 index 000000000..3636d44a3 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/smokeTex.png b/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/smokeTex.png new file mode 100644 index 000000000..8fe65fc8f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/CMFlare/smokeTex.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/CMSmoke/cmSmokeModel.mu b/BDArmory/Distribution/GameData/BDArmory/Models/CMSmoke/cmSmokeModel.mu new file mode 100644 index 000000000..a1d178d18 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/CMSmoke/cmSmokeModel.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/CMSmoke/smokeCm.png b/BDArmory/Distribution/GameData/BDArmory/Models/CMSmoke/smokeCm.png new file mode 100644 index 000000000..b72274d1a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/CMSmoke/smokeCm.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPBlast1.png b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPBlast1.png new file mode 100644 index 000000000..9cb243509 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPBlast1.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionL.mu b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionL.mu new file mode 100644 index 000000000..2b182f9d6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionL.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionM.mu b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionM.mu new file mode 100644 index 000000000..239004068 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionM.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionS.mu b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionS.mu new file mode 100644 index 000000000..13af90c8a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/EMPexplosion/EMPexplosionS.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH02.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH02.png new file mode 100644 index 000000000..6c482ae6c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH02.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH02_Emiss.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH02_Emiss.png new file mode 100644 index 000000000..af09b814b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH02_Emiss.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH3.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH3.png new file mode 100644 index 000000000..bdea097f8 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH3.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH3_Emiss.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH3_Emiss.png new file mode 100644 index 000000000..38a42bb9c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BH3_Emiss.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal1.mu b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal1.mu new file mode 100644 index 000000000..373b4b51b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal1.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal2.mu b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal2.mu new file mode 100644 index 000000000..c0d1cb5cc Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal2.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal2b.mu b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal2b.mu new file mode 100644 index 000000000..1e8dba8d5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletDecal/BulletDecal2b.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BDAc_BulletHole.mu b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BDAc_BulletHole.mu new file mode 100644 index 000000000..1a9b69cd9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BDAc_BulletHole.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BH01.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BH01.png new file mode 100644 index 000000000..af597ea74 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BH01.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BH02.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BH02.png new file mode 100644 index 000000000..745129cbb Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/BH02.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/SMMGrey.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/SMMGrey.png new file mode 100644 index 000000000..cd58db604 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/SMMGrey.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/Star02.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/Star02.png new file mode 100644 index 000000000..fe655678f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/Star02.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/bulletHit.mu b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/bulletHit.mu new file mode 100644 index 000000000..d5b111d7c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/bulletHit.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/bulletHit.png b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/bulletHit.png new file mode 100644 index 000000000..d2b87f34a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/bulletHit/bulletHit.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/largeExhaust.mu b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/largeExhaust.mu new file mode 100644 index 000000000..7332c4332 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/largeExhaust.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/mediumExhaust.mu b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/mediumExhaust.mu new file mode 100644 index 000000000..b540efea5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/mediumExhaust.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/smallExhaust.mu b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/smallExhaust.mu new file mode 100644 index 000000000..40a2c9dbc Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/smallExhaust.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_smokeExhaust.dds b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_smokeExhaust.dds new file mode 100644 index 000000000..a73e4e2b9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_smokeExhaust.dds differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_smokeExhaust.png b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_smokeExhaust.png new file mode 100644 index 000000000..310a0c89f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_smokeExhaust.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_sphere.dds b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_sphere.dds new file mode 100644 index 000000000..ef78e8d28 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_sphere.dds differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_sphere.png b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_sphere.png new file mode 100644 index 000000000..82370c2ec Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/exhaust/tex_sphere.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/30mmExplosion.mu b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/30mmExplosion.mu new file mode 100644 index 000000000..3229c0f0d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/30mmExplosion.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/ExpTex2.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/ExpTex2.png new file mode 100644 index 000000000..646a432bd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/ExpTex2.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/ExpTex4.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/ExpTex4.png new file mode 100644 index 000000000..cd96d8222 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/ExpTex4.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/bulletHit.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/bulletHit.png new file mode 100644 index 000000000..e5578aec7 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/bulletHit.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosion.mu b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosion.mu new file mode 100644 index 000000000..1151b9801 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosion.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosionLarge.mu b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosionLarge.mu new file mode 100644 index 000000000..84ba37be3 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosionLarge.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosionLarge2.mu b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosionLarge2.mu new file mode 100644 index 000000000..70fa2f753 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/explosionLarge2.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/fire4t.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/fire4t.png new file mode 100644 index 000000000..65473190f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/fire4t.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/flameD.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/flameD.png new file mode 100644 index 000000000..1f8670ee4 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/flameD.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/smokeCm.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/smokeCm.png new file mode 100644 index 000000000..b32789d34 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/smokeCm.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/smokeTex.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/smokeTex.png new file mode 100644 index 000000000..8202f4b27 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/smokeTex.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/explosion/spark.png b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/spark.png new file mode 100644 index 000000000..5359dd969 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/explosion/spark.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/shell/model.mu b/BDArmory/Distribution/GameData/BDArmory/Models/shell/model.mu new file mode 100644 index 000000000..0901852e8 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/shell/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Models/shell/texture.png b/BDArmory/Distribution/GameData/BDArmory/Models/shell/texture.png new file mode 100644 index 000000000..dbda34be0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Models/shell/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/model.mu new file mode 100644 index 000000000..3d259ac31 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/muzzle.png new file mode 100644 index 000000000..865a9e937 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/smoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/smoke.png new file mode 100644 index 000000000..ceb6fa6e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/sounds/VulcanCannon.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/sounds/VulcanCannon.ogg new file mode 100644 index 000000000..3b44fb56b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/sounds/VulcanCannon.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/sounds/VulcanEnd.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/sounds/VulcanEnd.ogg new file mode 100644 index 000000000..40d4c668c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/sounds/VulcanEnd.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/texture.png new file mode 100644 index 000000000..c185e9e5f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/vulcanTurret.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/vulcanTurret.cfg new file mode 100644 index 000000000..9d505f2a0 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/20mmVulcan/vulcanTurret.cfg @@ -0,0 +1,123 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaGatlingGun + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 0.76 + + + // --- node definitions --- + node_attach = 0.0, -0.397, 0, 0, -1, 0, 0 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Gun turrets + subcategory = 0 + bulkheadProfiles = srf + //title = Vulcan Turret + ///manufacturer = Bahamuto Dynamics + ////description = A 6 barrel 20x102mm rotary cannon. + title = #loc_BDArmory_part_20mmVulcan_title + manufacturer = #loc_BDArmory_part_manufacturer + description = #loc_BDArmory_part_20mmVulcan_description + + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 0,1,0,0,1 + + // --- standard part parameters --- + mass = 0.2 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 60 + maxTemp = 3600 + + stagingIcon = SOLID_BOOSTER + + + MODULE + { + name = ModuleTurret + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 90 + yawSpeedDPS = 90 + + minPitch = -8 + maxPitch = 65 + yawRange = 90 + + smoothRotation = true + smoothMultiplier = 10 + } + + MODULE + { + name = ModuleWeapon + + fireTransformName = fireTransform + + hasDeployAnim = true + deployAnimName = deployAnimation + hasFireAnimation = true + fireAnimName = fireAnimation + spinDownAnimation = true + + roundsPerMinute = 5500 + maxDeviation = 0.175 + maxEffectiveDistance = 2500 + maxTargetingRange = 5000 + + ammoName = 20x102Ammo + bulletType = 20x102mmHEBullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + useRippleFire = false + + weaponType = ballistic + + projectileColor = 255, 15, 0, 128//RGBA 0-255 + startColor = 255, 90, 0, 32 + fadeColor = false + + shellScale = 0.66 + + tracerStartWidth = 0.18 + tracerEndWidth = 0.18 + tracerLength = 0 + + //test + tracerDeltaFactor = 2.75 + tracerInterval = 3 + nonTracerWidth = 0.035 + + maxHeat = 3600 + heatPerShot = 36 + heatLoss = 820 + + fireSoundPath = BDArmory/Parts/20mmVulcan/sounds/VulcanCannon + overheatSoundPath = BDArmory/Parts/20mmVulcan/sounds/VulcanEnd + oneShotSound = false + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/50cal.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/50cal.cfg new file mode 100644 index 000000000..6ff1e1110 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/50cal.cfg @@ -0,0 +1,108 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaTurret + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 0.45 + + + // --- node definitions --- + node_attach = 0.0, -0.2049, 0, 0, -1, 0, 0 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Gun turrets + subcategory = 0 + bulkheadProfiles = srf + title = .50cal Turret + manufacturer = Bahamuto Dynamics + description = A dual barrel .50 cal machine gun. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 0,1,0,0,1 + + // --- standard part parameters --- + mass = 0.15 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 60 + maxTemp = 3600 + + stagingIcon = SOLID_BOOSTER + + + MODULE + { + name = ModuleTurret + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 120 + yawSpeedDPS = 120 + + maxPitch = 85 + minPitch = -8 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + } + + MODULE + { + name = ModuleWeapon + + fireTransformName = fireTransform + + hasDeployAnim = true + deployAnimName = deployAnimation + hasFireAnimation = true + fireAnimName = fireAnimation + + roundsPerMinute = 450 + maxDeviation = 0.65 + maxEffectiveDistance = 2500 + + weaponType = ballistic + ammoName = 50CalAmmo + bulletType = 12.7mmBullet + requestResourceAmount = 1 + shellScale = 0.463 + bulletDmgMult = 1.3 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + projectileColor = 255, 90, 0, 128 //RGBA 0-255 + startColor = 255, 105, 0, 70 + tracerStartWidth = 0.15 + tracerEndWidth = 0.05 + tracerLength = 0 + + maxHeat = 3600 + heatPerShot = 100 + heatLoss = 1000 + + fireSoundPath = BDArmory/Parts/50CalTurret/sounds/shot + overheatSoundPath = BDArmory/Parts/50CalTurret/sounds/turretOverheat + + + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/model.mu new file mode 100644 index 000000000..e3fca8617 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/muzzle.png new file mode 100644 index 000000000..865a9e937 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/sounds/shot.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/sounds/shot.ogg new file mode 100644 index 000000000..4fe440abc Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/sounds/shot.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/sounds/turretOverheat.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/sounds/turretOverheat.ogg new file mode 100644 index 000000000..e106d81e4 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/sounds/turretOverheat.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/texture.png new file mode 100644 index 000000000..c134f92b2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/50CalTurret/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/ABL.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/ABL.cfg new file mode 100644 index 000000000..15a51ab68 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/ABL.cfg @@ -0,0 +1,101 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaABL +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.573, 0, 0, -1, 0, 1 +node_stack_bottom = 0.0, -0.573, 0, 0, -1, 0, 1 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 7600 +category = none +bdacategory = Laser turrets +subcategory = 0 +bulkheadProfiles = srf +title = USAF Airborne Laser +manufacturer = Bahamuto Dynamics +description = A high powered laser for setting things on fire. Uses 350 electric charge per second. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.8 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 60 +maxTemp = 3600 + +stagingIcon = SOLID_BOOSTER + + + +MODULE +{ + name = ModuleTurret + + pitchTransformName = aimPitch + yawTransformName = aimRotate + + pitchSpeedDPS = 220 + yawSpeedDPS = 220 + + maxPitch = 90 + minPitch = -15 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 20 +} + +MODULE +{ + name = ModuleWeapon + + fireTransformName = fireTransform + + hasDeployAnim = true + deployAnimName = deployAnimation + hasFireAnimation = false + + maxEffectiveDistance = 5000 + maxTargetingRange = 5000 + maxDeviation = 0.0125 + + ammoName = ElectricCharge + requestResourceAmount = 350 + + weaponType = laser + laserDamage = 1600 + tanAngle = 0.0001 //controls how quickly damage scales down with distance + + projectileColor = 255, 20, 0, 128 //RGBA 0-255 + tracerStartWidth = 0.3 + tracerEndWidth = 0.3 + + maxHeat = 3600 + heatPerShot = 40 + heatLoss = 740 + + fireSoundPath = BDArmory/Parts/ABL/sounds/laser + chargeSoundPath = BDArmory/Parts/ABL/sounds/charge + overheatSoundPath = BDArmory/Parts/50CalTurret/sounds/turretOverheat +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/glasstest.png b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/glasstest.png new file mode 100644 index 000000000..11e1b3d43 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/glasstest.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/model.mu new file mode 100644 index 000000000..3889d1188 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/sounds/charge.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/sounds/charge.ogg new file mode 100644 index 000000000..1c5cfc204 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/sounds/charge.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/sounds/laser.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/sounds/laser.ogg new file mode 100644 index 000000000..f75d44b66 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/sounds/laser.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/texture.png new file mode 100644 index 000000000..6cadb0e9d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ABL/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.cfg new file mode 100644 index 000000000..8969a50a9 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.cfg @@ -0,0 +1,114 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaAgm86B +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = AGM86-17.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.25582, 0, 0, 1, 0, 0 +node_stack_top = 0.0, 0.25582, 0, 0, 1, 0, 0 +node_stack_base = 0.0, 0.0, -2.407, 0, 0, -1, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 2400 +category = none +bdacategory = Missiles +subcategory = 0 +bulkheadProfiles = srf +title = AGM-86C Cruise Missile +manufacturer = Bahamuto Dynamics +description = Long distance, sub-sonic, air-launched, GPS-guided cruise missile. This missile has no booster, so it must be launched while airborne at cruising speed. 2017 overhaul version. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 1.15 +dragModelType = default +maximum_drag = 0.01 +minimum_drag = 0.01 +angularDrag = 2 +crashTolerance = 5 +maxTemp = 3600 + + +MODULE +{ + name = MissileLauncher + shortName = AGM-86C + + thrust = 70 //KN thrust during boost phase + cruiseThrust = 11 //thrust during cruise phase + dropTime = 1 //how many seconds after release until engine ignites + boostTime = 3 //seconds of boost phase + cruiseTime = 180 //seconds of cruise phase + cruiseDelay = 0 + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 28 //degrees per second + + CruiseSpeed = 310 + CruisePredictionTime = 15 + CruiseAltitude = 250 + DetonationDistance = 0 + + decoupleSpeed = 5 + decoupleForward = false + + audioClipPath = BDArmory/Sounds/jet + boostClipPath = BDArmory/Sounds/jet + + optimumAirspeed = 310 + + homingType = Cruise + targetingType = gps + terminalManeuvering = false + + maxOffBoresight = 90 + lockedSensorFOV = 6 + agmDescentRatio = 1.2 + + rotationTransformName = rotationTransform + + maxAoA = 45 + + deployAnimationName = AGM8617deploy + deployedDrag = 0.011 + deployTime = 0.35 + + + aero = true + liftArea = 0.0075 + steerMult = 8 + maxTorque = 70 + torqueRampUp = 50 + //aeroSteerDamping = .55 + + exhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + minLaunchSpeed = 125 + minStaticLaunchRange = 700 + maxStaticLaunchRange = 40000 + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false +} +MODULE +{ + name = BDExplosivePart + tntMass = 1300 +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.mu new file mode 100644 index 000000000..4f7ff67a6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.png b/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.png new file mode 100644 index 000000000..b961c2516 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AGM86-17/AGM86-17.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/20mm.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/20mm.cfg new file mode 100644 index 000000000..8b5db6fae --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/20mm.cfg @@ -0,0 +1,66 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = baha20mmAmmo + module = Part + author = BahamutoD + + // --- asset parameters --- + //mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, -0.1129, 0, 0, -1, 0, 0 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 600 + category = none + bdacategory = Ammo + subcategory = 0 + bulkheadProfiles = srf + title = 20mm Ammunition Box + manufacturer = Bahamuto Dynamics + description = Ammo box containing 650 20x102mm rounds. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 0,1,0,1,1 + + // --- standard part parameters --- + mass = 0.01 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 7 + maxTemp = 3600 + + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + } + + MODULE + { + name = CFEnable + } + + MODEL + { + model = BDArmory/Parts/AmmoBox/model + texture = texture, BDArmory/Parts/AmmoBox/texture20x102 + } +DRAG_CUBE +{ + cube = Default,0.231,0.46985,0.1428,0.231,0.46985,0.1428,0.4151,0.49205,0.1111,0.4151,0.4834,0.3177,0.15,0.466,0.1399,0.15,0.46615,0.1399, 0,0.01306,-4.669E-09, 0.5282,0.297,0.7912 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/30mm.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/30mm.cfg new file mode 100644 index 000000000..4b3981a61 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/30mm.cfg @@ -0,0 +1,66 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = baha30mmAmmo + module = Part + author = BahamutoD + + // --- asset parameters --- + //mesh = model.mu + rescaleFactor = 1.2 + + + // --- node definitions --- + node_attach = 0.0, -0.1129, 0, 0, -1, 0, 0 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 1000 + category = none + bdacategory = Ammo + subcategory = 0 + bulkheadProfiles = srf + title = 30mm Ammunition Box + manufacturer = Bahamuto Dynamics + description = Ammo box containing 600 30x173mm rounds. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 0,1,0,1,1 + + // --- standard part parameters --- + mass = 0.01 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 7 + maxTemp = 3600 + + RESOURCE + { + name = 30x173Ammo + amount = 600 + maxAmount = 600 + } + + MODULE + { + name = CFEnable + } + + MODEL + { + model = BDArmory/Parts/AmmoBox/model + texture = texture, BDArmory/Parts/AmmoBox/texture30mm + } + DRAG_CUBE +{ + cube = Default,0.231,0.46985,0.1428,0.231,0.46985,0.1428,0.4151,0.49205,0.1111,0.4151,0.4834,0.3177,0.15,0.466,0.1399,0.15,0.46615,0.1399, 0,0.01306,-4.669E-09, 0.5282,0.297,0.7912 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/50cal.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/50cal.cfg new file mode 100644 index 000000000..a478b7a32 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/50cal.cfg @@ -0,0 +1,60 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = baha50CalAmmo +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.1129, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Ammo +subcategory = 0 +bulkheadProfiles = srf +title = 50cal Ammunition Box +manufacturer = Bahamuto Dynamics +description = Ammo box containing 1200 .50 cal rounds. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,1,1 + +// --- standard part parameters --- +mass = 0.01 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +RESOURCE +{ + name = 50CalAmmo + amount = 1200 + maxAmount = 1200 +} + +MODULE +{ + name = CFEnable +} + +DRAG_CUBE +{ + cube = Default,0.231,0.46985,0.1428,0.231,0.46985,0.1428,0.4151,0.49205,0.1111,0.4151,0.4834,0.3177,0.15,0.466,0.1399,0.15,0.46615,0.1399, 0,0.01306,-4.669E-09, 0.5282,0.297,0.7912 +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/BDAcUniversalAmmoBox.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/BDAcUniversalAmmoBox.cfg new file mode 100644 index 000000000..e60dfe312 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/BDAcUniversalAmmoBox.cfg @@ -0,0 +1,79 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = BDAcUniversalAmmoBox +module = Part +author = Spanner + + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 +buoyancy = -1 + +// --- node definitions --- +node_attach = 0.0, -0.1129, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Ammo +subcategory = 0 +bulkheadProfiles = srf +title = Universal Ammo Box +manufacturer = Bahamuto Dynamics +description = Scalable Ammo box containing whatever ammo you want to put in it. holds a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,1,1 + + +// --- standard part parameters --- +mass = 0.1 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + + MODULE + { + name = CFEnable + } + MODULE + { + name = ModuleAmmoSwitch//47 + resourceNames = Empty; 7.62x39Ammo; 7.7x56Ammo; 7.92x57mmMauser; 9x19mmParaAmmo; 50CalAmmo; 20x21Ammo; 20x102Ammo; 20x163Ammo; 23x115Ammo; 23x152Ammo; 25x137Ammo; 30x165Ammo; 30x173Ammo; 30x173HEAmmo; 37mmFlaKAmmo; 40x53Ammo; 40x53HeAmmo; 40x311Ammo; 54cmMortarShells; 57x438Ammo; TungstenShell; 75x714Ammo; 76x636Ammo; 3inchShells; 90mmShells; 100mmShells; 4p5inchQFShells; 105mmShells; 105mmHEShells; 120mmAmmo; 122mmQFShells; 130Shells; 5/62Shell; 138_140Shells; 152Shells; 155Shells; 180Shells; 203Shells; 12inShells; 356Shells; 356ApAmmo; 380Shells; M65ShellAmmo; 406mmNuclearShells; 16inchShells; 460Shells + resourceAmounts = 0; 500; 500; 500; 500; 400; 400; 400; 350; 350; 350; 350; 300; 300; 300; 300; 300; 300; 300; 200; 200; 200; 40; 40; 40; 30; 30; 30; 30; 30; 25; 25; 25; 20; 15; 15; 15; 15; 10; 8; 8; 8; 6; 4; 4; 4; 4 //47 + basePartMass = 0.1 + showInfo = true + displayCurrentTankCost = true + } + MODULE + { + name = TweakScale + type = surface + minScale = 0.25 + maxScale = 4 + defaultScale = 1 + scaleFactors = 0.5, 1, 2, 4 + incrementSlide = 0.05, 0.1, 0.2 + scaleNames = Half, Full, Double, Quadruple + } + MODEL + { + model = BDArmory/Parts/AmmoBox/model + texture = texture, BDArmory/Parts/AmmoBox/textureUni + } + DRAG_CUBE +{ + cube = Default,0.231,0.46985,0.1428,0.231,0.46985,0.1428,0.4151,0.49205,0.1111,0.4151,0.4834,0.3177,0.15,0.466,0.1399,0.15,0.46615,0.1399, 0,0.01306,-4.669E-09, 0.5282,0.297,0.7912 +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/UniversalAmmoBoxBDA.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/UniversalAmmoBoxBDA.cfg new file mode 100644 index 000000000..50fe3fc85 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/UniversalAmmoBoxBDA.cfg @@ -0,0 +1,79 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = UniversalAmmoBoxBDA +module = Part +author = Spanner + + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 +buoyancy = -1 + +// --- node definitions --- +node_attach = 0.0, -0.1129, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Ammo +subcategory = 0 +bulkheadProfiles = srf +title = Universal Ammo Box (Legacy) +manufacturer = Bahamuto Dynamics +description = (Obsolete - DO NOT USE - Requires Fire Spitter) Scalable Ammo box containing whatever ammo you want to put in it, does hold a selectable quantity of every ammunition type up to 16'1 inch that is currently used in KSP in association with BDAc Extra types can be added upon request (no fantasy ammo please) NOTE: this part still requires Fire Spitter, and is here for backwards compatability. Use the new UniversalAmmo part going forward. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,1,1 + + +// --- standard part parameters --- +mass = 0.1 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + + MODULE + { + name = CFEnable + } + MODULE + { + name = FSfuelSwitch//47 + resourceNames = Empty; 7.62x39Ammo; 7.7x56Ammo; 7.92x57mmMauser; 9x19mmParaAmmo; 50CalAmmo; 20x21Ammo; 20x102Ammo; 20x163Ammo; 23x115Ammo; 23x152Ammo; 25x137Ammo; 30x165Ammo; 30x173Ammo; 30x173HEAmmo; 37mmFlaKAmmo; 40x53Ammo; 40x53HeAmmo; 40x311Ammo; 54cmMortarShells; 57x438Ammo; TungstenShell; 75x714Ammo; 76x636Ammo; 3inchShells; 90mmShells; 100mmShells; 4p5inchQFShells; 105mmShells; 105mmHEShells; 120mmAmmo; 122mmQFShells; 130Shells; 5/62Shell; 138_140Shells; 152Shells; 155Shells; 180Shells; 203Shells; 12inShells; 356Shells; 356ApAmmo; 380Shells; M65ShellAmmo; 406mmNuclearShells; 16inchShells; 460Shells + resourceAmounts = 0; 500; 500; 500; 500; 400; 400; 400; 350; 350; 350; 350; 300; 300; 300; 300; 300; 300; 300; 200; 200; 200; 40; 40; 40; 30; 30; 30; 30; 30; 25; 25; 25; 20; 15; 15; 15; 15; 10; 8; 8; 8; 6; 4; 4; 4; 4 //47 + basePartMass = 0.1 + showInfo = true + displayCurrentTankCost = true + } + MODULE + { + name = TweakScale + type = surface + minScale = 0.25 + maxScale = 4 + defaultScale = 1 + scaleFactors = 0.5, 1, 2, 4 + incrementSlide = 0.05, 0.1, 0.2 + scaleNames = Half, Full, Double, Quadruple + } + MODEL + { + model = BDArmory/Parts/AmmoBox/model + texture = texture, BDArmory/Parts/AmmoBox/textureUni + } + DRAG_CUBE +{ + cube = Default,0.231,0.46985,0.1428,0.231,0.46985,0.1428,0.4151,0.49205,0.1111,0.4151,0.4834,0.3177,0.15,0.466,0.1399,0.15,0.46615,0.1399, 0,0.01306,-4.669E-09, 0.5282,0.297,0.7912 +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/cannonShell.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/cannonShell.cfg new file mode 100644 index 000000000..d5f793a60 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/cannonShell.cfg @@ -0,0 +1,65 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaCannonShellBox +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 2 + + +// --- node definitions --- +node_attach = 0.0, -0.1129, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Ammo +subcategory = 0 +bulkheadProfiles = srf +title = Cannon Ammunition Box +manufacturer = Bahamuto Dynamics +description = Ammo box containing 10 cannon shells. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,1,1 + +// --- standard part parameters --- +mass = 0.015 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +RESOURCE +{ + name = CannonShells + amount = 10 + maxAmount = 10 +} + +MODULE +{ + name = CFEnable +} + + MODEL + { + model = BDArmory/Parts/AmmoBox/model + texture = texture, BDArmory/Parts/AmmoBox/textureCannonShell + } +DRAG_CUBE +{ + cube = Default,0.231,0.46985,0.1428,0.231,0.46985,0.1428,0.4151,0.49205,0.1111,0.4151,0.4834,0.3177,0.15,0.466,0.1399,0.15,0.46615,0.1399, 0,0.01306,-4.669E-09, 0.5282,0.297,0.7912 +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/model.mu new file mode 100644 index 000000000..6c7af8425 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture.png new file mode 100644 index 000000000..c7b1c2b9e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture20x102.png b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture20x102.png new file mode 100644 index 000000000..85003bd75 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture20x102.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture30mm.png b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture30mm.png new file mode 100644 index 000000000..785b20678 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/texture30mm.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/textureCannonShell.png b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/textureCannonShell.png new file mode 100644 index 000000000..2bf47d379 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/textureCannonShell.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/textureUni.png b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/textureUni.png new file mode 100644 index 000000000..7b4868c32 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/AmmoBox/textureUni.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1panelArmor.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1panelArmor.cfg new file mode 100644 index 000000000..e0fce08aa --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1panelArmor.cfg @@ -0,0 +1,416 @@ +PART +{ +name = BD1x1slopeArmor +module = Part +author = SpannerMonkey +buoyancy = -1 +rescaleFactor = 1 + + MODEL + { + model = BDArmory/Parts/ArmorPlate/BD1x1slopeArmor + scale = 1.0, 1.0, 1.0 + } + + NODE + { + name = Node1 + transform = Node1 + size = 0 + method = FIXED_JOINT + } + NODE + { + + name = Node2 + transform = Node2 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node3 + transform = Node3 + size = 0 + method = FIXED_JOINT + } +node_attach = -0.5, 0, 0, 0, 0, 1, 0 + +TechRequired = composites +entryCost = 7200 +cost = 100 +category = Structural +bdacategory = Armor +subcategory = 0 +bulkheadProfiles = srf +title = BD 1x1 slope Armor +manufacturer = Bahamuto Dynamics +description = A sturdy 1x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float +attachRules = 1,1,1,1,1 + +// --- standard part parameters --- +mass = 0.0375 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 1 +crashTolerance = 80 +breakingForce = 200 +breakingTorque = 200 +maxTemp = 2000 +fuelCrossFeed = True +tags = armor Armo Ship Afv panel + + + + +} +//////////////////////////////////////////////////////////////////////// +PART +{ +name = BD2x1slopeArmor +module = Part +author = SpannerMonkey +buoyancy = -1 + MODEL + { + model = BDArmory/Parts/ArmorPlate/BD2x1slopeArmor + scale = 1.0, 1.0, 1.0 + } +rescaleFactor = 1 + NODE + { + name = Node1 + transform = Node1 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node2 + transform = Node2 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node3 + transform = Node3 + size = 0 + method = FIXED_JOINT + } +node_attach = -0.0, 0, 0.36, 0, 0, 1, 0 + +TechRequired = composites +entryCost = 7200 +cost = 100 +category = Structural +bdacategory = Armor +subcategory = 0 +bulkheadProfiles = srf +title = BD 2x1 slope Armor +manufacturer = Bahamuto Dynamics +description = A sturdy 2x1 slope Armor plate, perfect for constructing all sorts of things. PS does not float +attachRules = 1,1,1,1,1 + +// --- standard part parameters --- +mass = 0.075 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 1 +crashTolerance = 80 +breakingForce = 200 +breakingTorque = 200 +maxTemp = 2000 +fuelCrossFeed = True +tags = armor Armo Ship Afv panel + + + +} +///////////////////////////////////////////////////////////////////////////////// +PART +{ +name = BD1x1panelArmor +module = Part +author = SpannerMonkey +buoyancy = -1 + MODEL + { + model = BDArmory/Parts/ArmorPlate/BD1x1panelArmor + scale = 1.0, 1.0, 1.0 + } +rescaleFactor = 1 + NODE + { + name = Node1 + transform = Node1 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node2 + transform = Node2 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node3 + transform = Node3 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node4 + transform = Node4 + size = 0 + method = FIXED_JOINT + } +node_attach = -0.0, 0, 0.5, 0, 0, 1, 0 + +TechRequired = composites +entryCost = 7200 +cost = 100 +category = Structural +bdacategory = Armor +subcategory = 0 +bulkheadProfiles = srf +title = BD 1x1 panel Armor +manufacturer = Bahamuto Dynamics +description = A sturdy 1x1 Armor plate, perfect for constructing all sorts of things. PS does not float +attachRules = 1,1,1,1,1 + +// --- standard part parameters --- +mass = 0.075 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 1 +crashTolerance = 80 +breakingForce = 200 +breakingTorque = 200 +maxTemp = 2000 +fuelCrossFeed = True +tags = armor Armo Ship Afv panel + + + +} + +///////////////////////////////////////////////////////////////////////////////// +PART +{ +name = BD2x1panelArmor +module = Part +author = SpannerMonkey +buoyancy = -1 + MODEL + { + model = BDArmory/Parts/ArmorPlate/BD2x1panelArmor + scale = 1.0, 1.0, 1.0 + } +rescaleFactor = 1 + NODE + { + name = Node1 + transform = Node1 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node2 + transform = Node2 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node3 + transform = Node3 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node4 + transform = Node4 + size = 0 + method = FIXED_JOINT + } +node_attach = -0.0, 0, 0.5, 0, 0, 1, 0 + +TechRequired = composites +entryCost = 7200 +cost = 100 +category = Structural +bdacategory = Armor +subcategory = 0 +bulkheadProfiles = srf +title = BD 2x1 panel Armor +manufacturer = Bahamuto Dynamics +description = A sturdy 2x1 Armor plate, perfect for constructing all sorts of things. PS does not float +attachRules = 1,1,1,1,1 + +// --- standard part parameters --- +mass = 0.15 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 1 +crashTolerance = 80 +breakingForce = 200 +breakingTorque = 200 +maxTemp = 2000 +fuelCrossFeed = True +tags = armor Armo Ship Afv panel + + + +} +///////////////////// +PART +{ +name = BD3x1panelArmor +module = Part +author = SpannerMonkey +buoyancy = -1 + MODEL + { + model = BDArmory/Parts/ArmorPlate/BD3x1panelArmor + scale = 1.0, 1.0, 1.0 + } +rescaleFactor = 1 + NODE + { + name = Node1 + transform = Node1 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node2 + transform = Node2 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node3 + transform = Node3 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node4 + transform = Node4 + size = 0 + method = FIXED_JOINT + } +node_attach = -0.0, 0, 0.5, 0, 0, 1, 0 + +TechRequired = composites +entryCost = 7200 +cost = 100 +category = Structural +bdacategory = Armor +subcategory = 0 +bulkheadProfiles = srf +title = BD 3x1 panel Armor +manufacturer = Bahamuto Dynamics +description = A sturdy 3x1 Armor plate, perfect for constructing all sorts of things. PS does not float +attachRules = 1,1,1,1,1 + +// --- standard part parameters --- +mass = 0.225 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 1 +crashTolerance = 80 +breakingForce = 200 +breakingTorque = 200 +maxTemp = 2000 +fuelCrossFeed = True +tags = armor Armo Ship Afv panel + + + +} +/////////// +PART +{ +name = BD4x1panelArmor +module = Part +author = Spanner +buoyancy = -1 + MODEL + { + model = BDArmory/Parts/ArmorPlate/BD4x1panelArmor + scale = 1.0, 1.0, 1.0 + } +rescaleFactor = 1 + NODE + { + name = Node1 + transform = Node1 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node2 + transform = Node2 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node3 + transform = Node3 + size = 0 + method = FIXED_JOINT + } + NODE + { + name = Node4 + transform = Node4 + size = 0 + method = FIXED_JOINT + } +node_attach = -0.0, 0, 0.5, 0, 0, 1, 0 + +TechRequired = composites +entryCost = 7200 +cost = 100 +category = Structural +bdacategory = Armor +subcategory = 0 +bulkheadProfiles = srf +title = BD 4x1 panel Armor +manufacturer = Bahamuto Dynamics +description = A sturdy 4x1 Armor plate, perfect for constructing all sorts of things. PS does not float +attachRules = 1,1,1,1,1 + +// --- standard part parameters --- +mass = 0.3 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 1 +crashTolerance = 80 +breakingForce = 200 +breakingTorque = 200 +maxTemp = 2000 +fuelCrossFeed = True +tags = armor Armo Ship Afv panel + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1panelArmor.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1panelArmor.mu new file mode 100644 index 000000000..0b07e99b8 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1panelArmor.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1slopeArmor.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1slopeArmor.mu new file mode 100644 index 000000000..257878d9a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD1x1slopeArmor.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD2x1panelArmor.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD2x1panelArmor.mu new file mode 100644 index 000000000..b73b1b4cb Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD2x1panelArmor.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD2x1slopeArmor.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD2x1slopeArmor.mu new file mode 100644 index 000000000..246890c31 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD2x1slopeArmor.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD3x1panelArmor.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD3x1panelArmor.mu new file mode 100644 index 000000000..57103a846 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD3x1panelArmor.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD4x1panelArmor.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD4x1panelArmor.mu new file mode 100644 index 000000000..7f4d48caf Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BD4x1panelArmor.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BDGrey_NRM.png b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BDGrey_NRM.png new file mode 100644 index 000000000..a4764598c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/BDGrey_NRM.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/EYEGrey.png b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/EYEGrey.png new file mode 100644 index 000000000..2437e228a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/EYEGrey.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/armorpanelNRM.png b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/armorpanelNRM.png new file mode 100644 index 000000000..8988de27a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ArmorPlate/armorpanelNRM.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBD.png b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBD.png new file mode 100644 index 000000000..cd2a7b13f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBD.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBDAcMK1.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBDAcMK1.mu new file mode 100644 index 000000000..29fc13367 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBDAcMK1.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBDAcMk1.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBDAcMk1.cfg new file mode 100644 index 000000000..433979966 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBDAcMk1.cfg @@ -0,0 +1,131 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = GoalKeeperBDAcMk1 + module = Part + author = BahamutoD + + // --- asset parameters --- + MODEL +{ + model = BDArmory/Parts/GoalKeeperBDAcMk1/GoalKeeperBDAcMK1 +} + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, -0.0, 0, 0, -1, 0, 0 + node_stack_bottom = 0.0, -0.0, 0, 0, -1, 0, 2 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 1700 + cost = 750 + category = none + bdacategory = Gun turrets + subcategory = 0 + bulkheadProfiles = srf + title = GoalkeeperMk1 CIWS + manufacturer = Bahamuto Dynamics + description = A 7 barrel 30mm rotary cannon with full swivel range.This MK 1 version was found under a tarpaulin in a muddy field, Perfect for cash strapped militias and shifty governments (cheapskate version) Without Radar or detection equipment this turret requires the target information to be fed from an alternative source.(somebody pointing and shouting 'shoot that' has been found to be only marginally effective due to the excessive noise produced when the weapon fires) The 30mm high explosive rounds self detonate when they lose interest in flying, but this weapon does not feature automatic fuse timing. 30x173 + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 4 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 50 + maxTemp = 3600 + + stagingIcon = SOLID_BOOSTER + + MODULE + { + name = ModuleTurret + turretID = 0 + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 80 + yawSpeedDPS = 80 + + maxPitch = 85 + minPitch = -15 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.365 + minAudioPitch = 0.255 + maxVolume = 0.55 + } + + MODULE + { + name = ModuleWeapon + turretID = 0 + + fireTransformName = fireTransform + + hasDeployAnim = false + + hasFireAnimation = true + fireAnimName = GKBDAcFire + spinDownAnimation = true + + roundsPerMinute = 4200 + maxDeviation = 0.50 + maxEffectiveDistance = 4000 + maxTargetingRange = 5000 + + ammoName = 30x173Ammo + bulletType = 30x173Bullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + weaponType = ballistic + + projectileColor = 255, 20, 0, 160//RGBA 0-255 + startColor = 255, 30, 0, 24 + fadeColor = true + + tracerStartWidth = 0.18 + tracerEndWidth = 0.18 + tracerLength = 0 + tracerDeltaFactor = 2.75 + tracerInterval = 2 + nonTracerWidth = 0.065 + + maxHeat = 3600 + heatPerShot = 36 + heatLoss = 900 + + shellScale = 0.76 + + fireSoundPath = BDArmory/Parts/gau-8/sounds/GAU8Cannon + overheatSoundPath = BDArmory/Parts/gau-8/sounds/GAU8End + oneShotSound = false + + //explosion + airDetonation = true + airDetonationTiming = false + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode + + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/muzzle.png new file mode 100644 index 000000000..865a9e937 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/smoketest3.png b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/smoketest3.png new file mode 100644 index 000000000..9996b3a8e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk1/smoketest3.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/BDAcGKmk2.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/BDAcGKmk2.cfg new file mode 100644 index 000000000..5d2b0ce26 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/BDAcGKmk2.cfg @@ -0,0 +1,208 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = BDAcGKmk2 +module = Part +author = BahamutoD + +// --- asset parameters --- +MODEL +{ + model = BDArmory/Parts/GoalKeeperBDAcMk2/BDAcGKmk2 + +} +rescaleFactor = 1 + + + +// --- node definitions --- +node_attach = 0.0, -0.0, 0, 0, -1, 0, 0 +node_stack_bottom = 0.0, -0.0, 0, 0, -1, 0, 2 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 950 +category = none +bdacategory = Gun turrets +subcategory = 0 +bulkheadProfiles = srf +title = Goalkeeper MK2 CIWS +manufacturer = Bahamuto Dynamics +description = A 7 barrel 30mm rotary cannon with full swivel range. This MK 2 version was found covered in overspray and paint cans around the back of the hangar at the old KSC, developed from the MK1 to reduce the incidence of hearing loss amongst early target pointers. This MK2 has some slight advantages over the MK1, equipped with Infra red targeting and Radar data reciever The 30x173mm high explosive rounds are only a slight improvement over the MK1 ammunition in that they at least take slightly longer to lose interest in flying and so have a good chance of reaching the target, but this weapon was never equipped to feature automatic fuse timing. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 4.4 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 50 +maxTemp = 3600 + +stagingIcon = SOLID_BOOSTER + +MODULE + { + name = ModuleTurret + turretID = 0 + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 80 + yawSpeedDPS = 80 + + maxPitch = 85 + minPitch = -15 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.365 + minAudioPitch = 0.255 + maxVolume = 0.55 + } + + MODULE + { + name = ModuleWeapon + turretID = 0 + + fireTransformName = fireTransform + + hasDeployAnim = false + + hasFireAnimation = true + fireAnimName = BDAcGKmk2 + spinDownAnimation = true + + roundsPerMinute = 4200 + maxDeviation = 0.40 + maxEffectiveDistance = 4000 + maxTargetingRange = 5000 + + ammoName = 30x173Ammo + bulletType = 30x173Bullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + weaponType = ballistic + + projectileColor = 255, 20, 0, 160//RGBA 0-255 + startColor = 255, 30, 0, 24 + fadeColor = true + + tracerStartWidth = 0.18 + tracerEndWidth = 0.18 + tracerLength = 0 + tracerDeltaFactor = 2.75 + tracerInterval = 2 + nonTracerWidth = 0.065 + + maxHeat = 3600 + heatPerShot = 36 + heatLoss = 900 + + shellScale = 0.76 + + fireSoundPath = BDArmory/Parts/gau-8/sounds/GAU8Cannon + overheatSoundPath = BDArmory/Parts/gau-8/sounds/GAU8End + oneShotSound = false + + //explosion + airDetonation = true + airDetonationTiming = false + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode + + + } + + +MODULE +{ + name = ModuleTargetingCamera + cameraTransformName = camTransform + eyeHolderTransformName = eyeHolderTransform + zoomFOVs = 40,15,3,1 + gimbalLimit = 10 +} +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = Goalkeeper Data Receiver // if left empty part.title is used, but advised to set this to a nice printable text + //rwrThreatType = 0 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + //rotationTransformName = scanRotation + //turretID = 0 // if needed + resourceDrain = 0.25 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + //omnidirectional = true // false: boresight scan radar + //directionalFieldOfView = 90 // for omni and boresight + //boresightFOV = 10 // for boresight only + //scanRotationSpeed = 240 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + //lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + //maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = false // scanning/detecting targets (volume search) + canLock = false // locking/tracking targets (fire control) + canTrackWhileScan = false // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 350 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 120 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.1 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (very hard to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs aireal targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + + // nothing defined here as this radar does not support scanning on its own + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + + // nothing defined here as this radar does not support locking + } + + +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/BDAcGKmk2.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/BDAcGKmk2.mu new file mode 100644 index 000000000..4d2616d94 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/BDAcGKmk2.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/GoalKeeperBD.png b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/GoalKeeperBD.png new file mode 100644 index 000000000..cd2a7b13f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/GoalKeeperBD.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/muzzle.png new file mode 100644 index 000000000..865a9e937 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/smoketest3.png b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/smoketest3.png new file mode 100644 index 000000000..9996b3a8e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/GoalKeeperBDAcMk2/smoketest3.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/RBS-15-17.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/RBS-15-17.mu new file mode 100644 index 000000000..d405e0114 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/RBS-15-17.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/RBS15-17.png b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/RBS15-17.png new file mode 100644 index 000000000..580445277 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/RBS15-17.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/rbs15-17.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/rbs15-17.cfg new file mode 100644 index 000000000..241841e43 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17/rbs15-17.cfg @@ -0,0 +1,109 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaRBS-15Cruise + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.254, 0, 0, 1, 0, 0 + node_stack_top = 0.0, 0.254, 0, 0, 1, 0, 0 + node_stack_base = 0.0, 0.0, -2.179, 0, 0, -1, 0 + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 2000 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = RBS-15 Cruise Missile + manufacturer = Bahamuto Dynamics + description = Long distance, multi-platform high-speed cruise missile with boosters. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 1.15 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + thrust = 100 //KN thrust during boost phase + cruiseThrust = 15 //thrust during cruise phase + dropTime = 0 //how many seconds after release until engine ignites + boostTime = 5 //seconds of boost phase + cruiseTime = 118 //seconds of cruise phase + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 20 //degrees per second + + CruiseSpeed = 310 + optimumAirspeed = 310 + CruisePredictionTime = 15 + CruiseAltitude = 250 + DetonationDistance = 0 + + decoupleSpeed = 15 + decoupleForward = true + + audioClipPath = BDArmory/Sounds/jet + boostClipPath = BDArmory/Sounds/rocketLoop + + homingType = Cruise + targetingType = gps + + maxOffBoresight = 180 + lockedSensorFOV = 7 + agmDescentRatio = 1.2 + + rotationTransformName = rotationTransform + + maxAoA = 45 + + aero = true + liftArea = 0.0055 + steerMult = 5 + maxTorque = 23 + torqueRampUp = 25 + terminalManeuvering = false + + boosterMass = 0.25 + boosterDecoupleSpeed = 7 + decoupleBoosters = true + boostTransformName = boosterTransform + boostExhaustTransformName = boostExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + exhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + minStaticLaunchRange = 700 + maxStaticLaunchRange = 40000 + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + + } + MODULE + { + name = BDExplosivePart + tntMass = 300 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/RBS-15-17.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/RBS-15-17.mu new file mode 100644 index 000000000..352eb7ee0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/RBS-15-17.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/RBS15-17.png b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/RBS15-17.png new file mode 100644 index 000000000..580445277 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/RBS15-17.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/rbs15-17AL.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/rbs15-17AL.cfg new file mode 100644 index 000000000..a67303a5c --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/RBS-15-17AL/rbs15-17AL.cfg @@ -0,0 +1,103 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaRBS-15ALCruise + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.254, 0, 0, 1, 0, 0 + node_stack_top = 0.0, 0.254, 0, 0, 1, 0, 0 + node_stack_base = 0.0, 0.0, -2.179, 0, 0, -1, 0 + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 2000 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = RBS-15 Air launched Cruise Missile + manufacturer = Bahamuto Dynamics + description = Long distance, multi-platform high-speed cruise missile Air launched variant without external boosters + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 1.15 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + thrust = 100 //KN thrust during boost phase + cruiseThrust = 15 //thrust during cruise phase + dropTime = 2 //how many seconds after release until engine ignites + boostTime = 1.2 //seconds of boost phase + cruiseTime = 120 //seconds of cruise phase + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 25 //degrees per second + + CruiseSpeed = 310 + optimumAirspeed = 310 + CruisePredictionTime = 15 + CruiseAltitude = 250 + DetonationDistance = 0 + + decoupleSpeed = 2 + decoupleForward = false + + audioClipPath = BDArmory/Sounds/jet + boostClipPath = BDArmory/Sounds/rocketLoop + + homingType = Cruise + targetingType = gps + + maxOffBoresight = 180 + lockedSensorFOV = 7 + agmDescentRatio = 1.2 + + rotationTransformName = rotationTransform + + maxAoA = 45 + + aero = true + liftArea = 0.0053 + steerMult = 8 + maxTorque = 65 + torqueRampUp = 50 + terminalManeuvering = false + + minStaticLaunchRange = 700 + maxStaticLaunchRange = 40000 + + exhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + } + MODULE + { + name = BDExplosivePart + tntMass = 300 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/SaturnAL31/SaturnAL31.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/SaturnAL31/SaturnAL31.cfg new file mode 100644 index 000000000..e0855afcb --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/SaturnAL31/SaturnAL31.cfg @@ -0,0 +1,417 @@ +PART +{ + name = SaturnAL31 + module = Part + author = TheKurgan + MODEL + { + model = Squad/Parts/Engine/jetEngines/turboJet + } + rescaleFactor = 1 + node_stack_top = 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 + CoMOffset = 0.0, 1.2, 0.0 + TechRequired = supersonicFlight + entryCost = 9000 + cost = 2000 + category = Engine + subcategory = 0 + bulkheadProfiles = size1 + title = Saturn AL-31FM1 Afterburning Jet Engine + manufacturer = KTech + description = A high performance jet engine with a variable geometry thrust vectoring nozzle and an afterburner for extra thrust. Based on the highly popular J-404 engine, KTech engineers saw the potential of (highly) modifying the commercial variant into a formidable powerplant for military use. After seeing the potential of the engine, the BDAc group immediately licensed it for their new MkIII test drone. + attachRules = 1,0,1,0,0 + mass = 1.05 + skinInternalConductionMult = 4.0 + emissiveConstant = 0.8 // engine nozzles are good at radiating. + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 7 + maxTemp = 2600 + tags = fighter jet + MODULE + { + name = MultiModeEngine + primaryEngineID = Dry + secondaryEngineID = Wet + carryOverThrottle = True + autoSwitchAvailable = False + primaryEngineModeDisplayName = Dry + secondaryEngineModeDisplayName = Wet + } + + MODULE + { + name = ModuleEnginesFX + engineID = Dry + thrustVectorTransformName = thrustTransform + exhaustDamage = True + ignitionThreshold = 0.1 + minThrust = 0 + maxThrust = 92 + heatProduction = 15 + useEngineResponseTime = True + engineAccelerationSpeed = 0.5 + engineDecelerationSpeed = 0.5 + useVelocityCurve = False + flameoutEffectName = flameout + powerEffectName = power_dry + //runningEffectName = running_thrust + engageEffectName = engage + disengageEffectName = disengage + spoolEffectName = running_dry + engineSpoolIdle = 0.05 + engineSpoolTime = 2.0 + EngineType = Turbine + exhaustDamageMultiplier = 5 + PROPELLANT + { + name = LiquidFuel + resourceFlowMode = STAGE_STACK_FLOW_BALANCE + ratio = 1 + DrawGauge = True + } + PROPELLANT + { + name = IntakeAir + ignoreForIsp = True + ratio = 40 + } + atmosphereCurve + { + key = 0 9600 0 0 + } + // Jet params + atmChangeFlow = True + useVelCurve = True + useAtmCurve = True + flowMultCap = 1.1 + machLimit = 1.75 + machHeatMult = 20.0 + velCurve + { + key = 0 1 -0.1543096 -0.1543096 + key = 0.61 0.79 0 0 + key = 1.5 0.964 0 0 + key = 2 0.31 -3.278422 -3.278422 + key = 2.1 0 -0.9205825 -0.9205825 + } + atmCurve + { + key = 0 0 -0.009380879 0.02675156 + key = 0.1475 0 0 0 + key = 0.21 0.75 10.11998 9.912155 + key = 0.2653 1 2.007882 1.716759 + key = 1.013 1 0.0005999365 -0.0007497668 + } + } + MODULE + { + name = ModuleEnginesFX + engineID = Wet + thrustVectorTransformName = thrustTransform + exhaustDamage = True + ignitionThreshold = 0.1 + minThrust = 0 + maxThrust = 152 + heatProduction = 75 + useEngineResponseTime = True + engineAccelerationSpeed = 0.8 + engineDecelerationSpeed = 0.8 + useVelocityCurve = False + flameoutEffectName = flameout + //powerEffectName = running_wet + runningEffectName = power_wet + engageEffectName = engage + disengageEffectName = disengage + spoolEffectName = running_wet + engineSpoolIdle = 0.05 + engineSpoolTime = 2.0 + EngineType = Turbine + exhaustDamageMultiplier = 20 + PROPELLANT + { + name = LiquidFuel + resourceFlowMode = STAGE_STACK_FLOW_BALANCE + ratio = 1 + DrawGauge = True + } + PROPELLANT + { + name = IntakeAir + ignoreForIsp = True + ratio = 12 + } + atmosphereCurve + { + key = 0 5200 0 0 + } + // Jet params + atmChangeFlow = True + useVelCurve = True + useAtmCurve = True + flowMultCap = 1.1 + machLimit = 2.5 + machHeatMult = 20.0 + + velCurve + { + key = 0 1.25 0 0 + key = 0.25 1.7 2 2 + key = 1.8 2.8 0 0 + key = 2.5 2.25 -1.75 -1.75 + key = 4 0 0 0 + } + + atmCurve + { + key = 0 0 -0.009380879 0.02675156 + key = 0.1475 0 0 0 + key = 0.21 0.75 10.11998 9.912155 + key = 0.2653 1 2.007882 1.716759 + key = 1.013 1 0.0005999365 -0.0007497668 + } + } + + MODULE + { + name = FXModuleAnimateThrottle + animationName = TurboJetNozzleDry + responseSpeed = 0.05 + layer = 1 + dependOnEngineState = True + dependOnThrottle = True + engineName = Dry + weightOnOperational = True + } + MODULE + { + name = FXModuleAnimateThrottle + animationName = TurboJetNozzleWet + responseSpeed = 0.08 + layer = 2 + dependOnEngineState = True + dependOnThrottle = True + engineName = Wet + weightOnOperational = True + } + MODULE + { + name = FXModuleAnimateThrottle + animationName = TurboJetHeat + responseSpeed = 0.0005 + layer = 3 + dependOnEngineState = True + engineName = Wet + } + MODULE + { + name = ModuleGimbal + gimbalTransformName = Gimbal + gimbalRange = 10 + gimbalResponseSpeed = 9 + useGimbalResponseSpeed = true + } + + MODULE + { + name = FXModuleConstrainPosition + matchRotation = false + matchPosition = true + CONSTRAINFX + { + targetName = NozzlePoint + moversName = Nozzle + } + } + + MODULE + { + name = ModuleAlternator + engineName = Wet + outputName = Alternator (Wet) + RESOURCE + { + name = ElectricCharge + rate = 5.0 + } + } + MODULE + { + name = ModuleAlternator + engineName = Dry + outputName = Alternator (Dry) + RESOURCE + { + name = ElectricCharge + rate = 3.0 + } + } + MODULE + { + name = ModuleSurfaceFX + thrustProviderModuleIndex = 1 + fxMax = 0.6 + maxDistance = 25 + falloff = 2 + thrustTransformName = thrustTransform + } + MODULE + { + name = ModuleSurfaceFX + thrustProviderModuleIndex = 2 + fxMax = 0.6 + maxDistance = 25 + falloff = 2 + thrustTransformName = thrustTransform + } + EFFECTS + { + + running_dry + { + PREFAB_PARTICLE + { + prefabName = fx_smokeTrail_light + transformName = smokePoint + emission = 0.0 0.0 + emission = 0.05 0.0 + emission = 0.075 0.25 + emission = 1.0 1.25 + speed = 0.0 0.25 + speed = 1.0 1.0 + localOffset = 0, 0, 1 + localRotation = 1, 0, 0, -90 + } + AUDIO + { + channel = Ship + clip = sound_jet_low + volume = 0.0 0.0 + volume = 0.05 0.9 + volume = 1.0 1.0 + pitch = 0.0 0.5 + pitch = 0.05 0.6 + pitch = 0.33 1.0 + pitch = 1.0 1.2 + loop = true + } + } + + power_dry + { + AUDIO + { + channel = Ship + clip = sound_jet_deep + volume = 0.0 0.0 + volume = 0.05 0.4 + volume = 1.0 0.9 + pitch = 0.0 0.8 + pitch = 1.0 1.4 + loop = true + } + } + running_wet + { + PREFAB_PARTICLE + { + prefabName = fx_smokeTrail_light + transformName = smokePoint + emission = 0.0 0.0 + emission = 0.05 0.0 + emission = 0.075 0.5 + emission = 1.0 1.25 + speed = 0.0 0.25 + speed = 1.0 1.0 + localOffset = 0, 0, 1 + localRotation = 1, 0, 0, -90 + } + AUDIO + { + channel = Ship + clip = sound_jet_low + volume = 0.0 0.0 + volume = 0.05 0.9 + volume = 1.0 1.0 + pitch = 0.0 0.5 + pitch = 0.05 0.6 + pitch = 0.33 1.0 + pitch = 1.0 1.2 + loop = true + } + } + power_wet + { + + AUDIO + { + channel = Ship + clip = sound_rocket_spurts + volume = 0.0 0.0 + volume = 0.1 0.3 + volume = 1.0 0.5 + pitch = 0.0 0.5 + pitch = 0.33 0.8 + pitch = 1.0 1.5 + loop = true + } + MODEL_MULTI_PARTICLE + { + modelName = Squad/FX/afterburner_flame + transformName = smokePoint + emission = 0.0 0.0 + emission = 0.05 0.05 + emission = 0.33 0.1 + emission = 1.0 1.0 + speed = 0.0 0.0 + speed = 0.05 0.05 + speed = 0.33 0.16 + speed = 1.0 1.0 + energy = 0.0 1.5 + energy = 0.33 1.0 + energy = 1.0 1.0 + } + } + engage + { + AUDIO + { + channel = Ship + clip = sound_vent_medium + volume = 1.0 + pitch = 2.0 + loop = false + } + } + disengage + { + AUDIO + { + channel = Ship + clip = sound_vent_soft + volume = 1.0 + pitch = 2.0 + loop = false + } + } + flameout + { + PREFAB_PARTICLE + { + prefabName = fx_exhaustSparks_flameout_2 + transformName = smokePoint + oneShot = true + } + AUDIO + { + channel = Ship + clip = sound_explosion_low + volume = 1.0 + pitch = 2.0 + loop = false + } + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/SaturnAL31/SaturnAL31_TS.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/SaturnAL31/SaturnAL31_TS.cfg new file mode 100644 index 000000000..3774a2c5b --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/SaturnAL31/SaturnAL31_TS.cfg @@ -0,0 +1,9 @@ +@PART[SaturnAL31]:NEEDS[TweakScale] +{ + #@TWEAKSCALEBEHAVIOR[Engine]/MODULE[TweakScale] { } + %MODULE[TweakScale] + { + type = stack + defaultScale = 1.25 + } +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarPod1A.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarPod1A.cfg new file mode 100644 index 000000000..1d6874bb1 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarPod1A.cfg @@ -0,0 +1,125 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = BDAsonarPod1A +module = Part +author = Spanner + +// --- asset parameters --- +buoyancy = 0 +MODEL + { + model = BDArmory/Parts/SonarPod/BDAsonarPod1A + scale = 1.0, 1.0, 1.0 + } + rescaleFactor = 1 + + + +// --- node definitions --- +node_attach = 0.0, -0.0, 0, 0, 0, -1 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Radars +subcategory = 0 +bulkheadProfiles = srf + +title = BDA MK1 Sonar Pod +manufacturer = SM Armory +description = BDA MK1 Sonar Pod can only detect splashed and submerged vessels mount below waterline for best results. As a hull-mounted sonar it has limited range and sensitivity only. + +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.001 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = BDA MK1 Sonar Pod // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 6 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = shaft//rotationTransform + //turretID = 0 // if needed + resourceDrain = 1.0 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = true // false: boresight scan radar + directionalFieldOfView = 90 // for omni and boresight + //boresightFOV = 10 // for boresight only + scanRotationSpeed = 90 // degress per second + lockRotationSpeed = 90 // only relevant if canLock + //lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = true // locking/tracking targets (fire control) + canTrackWhileScan = true // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 15 // DEPRECATED, NO LONGER USED! use detection float curve! + //minLockedSignalThreshold = 90 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.4 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 5 0 //between 0 and 5 km the min cross section is 0, thus assured detection of everything + key = 11 10 + key = 20 55 //at 20km range a rcs of 55 m^2 can be detected + key = 40 150 + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + key = 0.0 0 + key = 5 5 //needs higher rcs to lock at comparable range + key = 11 20 + key = 20 75 + key = 40 200 // at max range only very large ("noisy") targets can be tracked + } + + +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarPod1A.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarPod1A.mu new file mode 100644 index 000000000..10ae45ce2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarPod1A.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarpodA.png b/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarpodA.png new file mode 100644 index 000000000..b7c828fb5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/SonarPod/BDAsonarpodA.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDA.png b/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDA.png new file mode 100644 index 000000000..d52b982b8 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDA.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDATorpedo.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDATorpedo.cfg new file mode 100644 index 000000000..b84672b35 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDATorpedo.cfg @@ -0,0 +1,121 @@ +PART +{ + name = StingRayBDATorpedo + module = Part + mesh = model.mu + author = Spanner + + rescaleFactor = 1 +NODE +{ + name = Node1 + transform = Node1 + size = 0 + method = FIXED_JOINT //FIXED_JOINT, HINGE_JOINT, LOCKED_JOINT, MERGED_PHYSICS or NO_PHYSICS +} +NODE +{ + name = Node2 + transform = Node2 + size = 0 + method = FIXED_JOINT //FIXED_JOINT, HINGE_JOINT, LOCKED_JOINT, MERGED_PHYSICS or NO_PHYSICS +} + + buoyancy = 0.2 + CoMOffset = 0.0, -0.0, 0.4 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 470 + category = none + bdacategory = Torpedoes + subcategory = 0 + bulkheadProfiles = srf + + title = Sting Ray BDA LightWeight Torpedo + manufacturer = BD Armory // manufactured by SM Armory + + description = Sting Ray Light Weight Torpedo Ship launch, and heli launch airdrop do not use in submarines. Interesting fact , you can fit 16 of these in a pac launcher, though using them in such a device without proper training has been the cause of much weeping and letters wriiten + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,0,0,0,0 + + // --- standard part parameters --- + mass = 0.2655 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 300 + breakingForce = 5000 + breakingTorque = 5000 + maxTemp = 3200 + tags = torpedo + + +MODULE +{ + name = MissileLauncher + + shortName = SRayBDA + + thrust = 47.8 //KN thrust during boost phase + cruiseThrust = 22.2 //thrust during cruise phase + cruiseDelay = 0 /// delay between boost ending and cruise starting, only used for large ship launched and air drop versions + dropTime = 8 //how many seconds after release until engine ignites extended drop time allows torpedo to sink to depth, too short a drop time will turn it into a very wayward missile + boostTime = 2 //seconds of boost phase + cruiseTime = 480 //seconds of cruise phase + //spoolEngine = true // N/A special cases only + + guidanceActive = true //missile has guidanceActive + + decoupleSpeed = 1.5 //f 0.1 steps max value 10 + decoupleForward = true // throws the torpedo out of the tube + isTubeLoaded = true + + optimumAirspeed = 45 + torpedo = true + waterImpactTolerance = 100 + + aero = true + liftArea = 0.0037 + steerMult = 2 + maxTorque = 45 + maxAoA = 30 + aeroSteerDamping = 5 + + missileType = torpedo // used by code to determine characteristics + homingType = AAM + targetingType = radar + + radarLOAL = true + activeRadarRange = 8000 + maxOffBoresight = 270 + lockedSensorFOV = 7 + maxTurnRateDPS = 40 //degrees per second + + proxyDetonate = false + DetonationDistance = 0 + + audioClipPath = BDArmory/Sounds/TorpPropFX + exhaustPrefabPath = BDArmory/FX/TorpWake + boostExhaustPrefabPath = BDArmory/FX/jetdriveWake + boostTransformName = boostTransform + boostExhaustTransformName = boostTransform + radarLOAL = true + minStaticLaunchRange = 200 + maxStaticLaunchRange = 8000 + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = true +} + +MODULE +{ + name = BDExplosivePart + tntMass = 120 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDATorpedo.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDATorpedo.mu new file mode 100644 index 000000000..8b35e8791 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/StingRayBDA/StingRayBDATorpedo.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/adjustableRail.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/adjustableRail.cfg new file mode 100644 index 000000000..4b8a4208d --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/adjustableRail.cfg @@ -0,0 +1,56 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaAdjustableRail + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.042, 0.0168, 0, 1, 0, 0 + node_stack_top = 0.0, 0.042, 0.0168, 0, 1, 0, 0 + node_stack_bottom = 0.0, -0.06987453, 0.0168, 0, -1, 0, 0 + node_stack_left = 0.04429158, -0.0235229, 0.0168, 1,0,0, 0 + node_stack_right = -0.04429158, -0.0235229, 0.0168, -1,0,0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Missile turrets + subcategory = 0 + bulkheadProfiles = srf + title = Adjustable Missile Rail + manufacturer = Bahamuto Dynamics + description = A rail for mounting missiles. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,1,1,1 + + // --- standard part parameters --- + mass = 0.01 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 60 + maxTemp = 3600 + + PhysicsSignificance = 1 + + + MODULE + { + name = BDAdjustableRail + stackNodePosition = bottom,0.0,-0.06987453,0.03889469;left,0.04429158,-0.0235229,0.0168;right,-0.04429158,-0.0235229,0.0168 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/model.mu new file mode 100644 index 000000000..37c886db0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/texture.png new file mode 100644 index 000000000..83d7ab793 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/adjustableRail/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/SAI1.png b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/SAI1.png new file mode 100644 index 000000000..8da9e7dcc Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/SAI1.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/model.mu new file mode 100644 index 000000000..5f4f356ad Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/part.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/part.cfg new file mode 100644 index 000000000..16b2a4623 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/part.cfg @@ -0,0 +1,52 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bdPilotAI +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.02069652, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Control +subcategory = 0 +bulkheadProfiles = srf +title = AI Pilot Flight Computer +manufacturer = Bahamuto Dynamics +description = Flies your plane on combat air patrol missions without using your hands. Tune the values based on your plane's unique flight characteristics. Please activate engines manually. Works in conjunction with a weapon manager in guard mode (attach and configure separately). (EXPERIMENTAL) +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.001 +dragModelType = default +maximum_drag = 0.02 +minimum_drag = 0.02 +angularDrag = 2 +crashTolerance = 60 +maxTemp = 3600 + +PhysicsSignificance = 1 + + +MODULE +{ + name = BDModulePilotAI +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/surface_ai.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/surface_ai.cfg new file mode 100644 index 000000000..7f1980808 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/surface_ai.cfg @@ -0,0 +1,55 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bdShipAI +module = Part +author = Spanner +MODEL +{ + model = BDArmory/Parts/aiPilot/model + scale = 1.0, 1.0, 1.0 + texture = texture, BDArmory/Parts/aiPilot/SAI1 +} +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.02069652, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Control +subcategory = 0 +bulkheadProfiles = srf +title = AI Surface Operation Driver +manufacturer = Bahamuto Dynamics +description = Drives your car/tank/boat/etc on combat and patrol missions over the lands and seas without using your hands. Tune the values based on your ship's unique characteristics. Please activate engines manually. Works in conjunction with a weapon manager in guard mode (attach and configure separately). (EXPERIMENTAL) +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.001 +dragModelType = default +maximum_drag = 0.02 +minimum_drag = 0.02 +angularDrag = 2 +crashTolerance = 60 +maxTemp = 3600 + +PhysicsSignificance = 1 + + +MODULE +{ + name = BDModuleSurfaceAI +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/texture.png new file mode 100644 index 000000000..e91bae270 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/aiPilot/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/amraam.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/amraam.cfg new file mode 100644 index 000000000..f159bd513 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/amraam.cfg @@ -0,0 +1,102 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaAim120 + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.09, -0.984, 0, 1, 0, 0 + node_stack_top = 0.0, 0.09, -0.175, 0, 1, 0, 0 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 2000 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = AIM-120 AMRAAM Missile + manufacturer = Bahamuto Dynamics + description = Medium range radar guided homing missile. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.152 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + shortName = AIM-120 + + thrust = 55 //KN thrust during boost phase + cruiseThrust = 25 //thrust during cruise phase + dropTime = 0.55 //how many seconds after release until engine ignites + boostTime = 2.2 //seconds of boost phase + cruiseTime = 120 //seconds of cruise phase + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 35 //degrees per second + + decoupleSpeed = 5 + + audioClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + + boostTransformName = boostTransform + boostExhaustTransformName = boostTransform + + optimumAirspeed = 1372 + + aero = true + liftArea = 0.0020 + steerMult = 8 + maxTorque = 60 + maxAoA = 30 + + missileType = missile + homingType = aam + targetingType = radar + activeRadarRange = 6000 + maxOffBoresight = 120 + lockedSensorFOV = 7 + + minStaticLaunchRange = 500 + maxStaticLaunchRange = 25000 + + radarLOAL = true + + engageAir = true + engageMissile = false + engageGround = false + engageSLW = false + } + + MODULE + { + name = BDExplosivePart + tntMass = 25 + } + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/amraam_emp.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/amraam_emp.cfg new file mode 100644 index 000000000..b230701f5 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/amraam_emp.cfg @@ -0,0 +1,109 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = AMRAAM_EMP + module = Part + author = BahamutoD + + // --- asset parameters --- + MODEL + { + model = BDArmory/Parts/aim-120/model + } + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.09, -0.984, 0, 1, 0, 0 + node_stack_top = 0.0, 0.09, -0.175, 0, 1, 0, 0 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 2000 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = AMRAAM EMP Missile + manufacturer = Bahamuto Dynamics + description = Medium range radar guided homing missile equipped with the latest miniaturized EMP warhead. While the pulse radius is not huge (100 meters), it is quite effective. The missile does minimal structural damage, but renders all electronic devices within it's blast radius inoperable. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.152 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + shortName = AIM-120 + + thrust = 55 //KN thrust during boost phase + cruiseThrust = 25 //thrust during cruise phase + dropTime = 0.55 //how many seconds after release until engine ignites + boostTime = 2.2 //seconds of boost phase + cruiseTime = 120 //seconds of cruise phase + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 35 //degrees per second + DetonationDistance = 20 + decoupleSpeed = 5 + + audioClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + + boostTransformName = boostTransform + boostExhaustTransformName = boostTransform + + optimumAirspeed = 1372 + + aero = true + liftArea = 0.0020 + steerMult = 8 + maxTorque = 60 + maxAoA = 30 + + missileType = missile + homingType = aam + targetingType = radar + activeRadarRange = 6000 + maxOffBoresight = 120 + lockedSensorFOV = 7 + + minStaticLaunchRange = 500 + maxStaticLaunchRange = 25000 + + radarLOAL = true + + engageAir = true + engageMissile = false + engageGround = true + engageSLW = false + } + + MODULE + { + name = BDExplosivePart + tntMass = 0.01 + explModelPath = BDArmory/Models/EMPexplosion/EMPexplosionS + } + MODULE + { + name = ModuleEMP + proximity = 100 + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/model.mu new file mode 100644 index 000000000..070c4822e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/texture.png new file mode 100644 index 000000000..0b92a2d8b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/aim-120/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/awacsRadar.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/awacsRadar.cfg new file mode 100644 index 000000000..905b3f4db --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/awacsRadar.cfg @@ -0,0 +1,118 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = awacsRadar +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = radar2.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Radars +subcategory = 0 +bulkheadProfiles = srf +title = AWACS Detection Radar +manufacturer = Bahamuto Dynamics +description = A large radar capable of detecting objects from a long distance. This radar does NOT have the capability of tracking or locking targets. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 1.45 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = AWACS Detection Radar // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 2 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = rotationTransform + //turretID = 0 // if needed + resourceDrain = 1.25 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = true // false: boresight scan radar + directionalFieldOfView = 90 // for omni and boresight + //boresightFOV = 10 // for boresight only + scanRotationSpeed = 110 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + //lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + //maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = false // locking/tracking targets (fire control) + canTrackWhileScan = false // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 50 // DEPRECATED, NO LONGER USED! use detection float curve! + //minLockedSignalThreshold = 90 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.2 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 10 0 //between 0 and 10 km the min cross section is 0, thus assured detection of everything + key = 11 1 + key = 20 5 //at 20km range a rcs of 5 m^2 can be detected + key = 40 15 + key = 80 30 //max range 80km, rcs detectable is 30m^2 + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + + // nothing defined here as this radar does not support locking + } + +} + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/model.mu new file mode 100644 index 000000000..c839103a8 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/tex_awacs.png b/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/tex_awacs.png new file mode 100644 index 000000000..6d3ee6dd1 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/awacsRadar/tex_awacs.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/model.mu new file mode 100644 index 000000000..1529e1a5c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/part.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/part.cfg new file mode 100644 index 000000000..a037c3605 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/part.cfg @@ -0,0 +1,71 @@ +PART +{ + + +// --- general parameters --- +name = bdammGuidanceModule +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + +// --- node definitions --- +// definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z + +node_attach = 0.0, -0.0146915, 0, 0, -1, 0, 0 + + + +// --- FX definitions --- + + +// --- editor parameters --- +TechRequired = advAerodynamics +entryCost = 6800 +cost = 180 +category = none +bdacategory = Control +subcategory = 0 +bulkheadProfiles = srf +title = Modular Missile Guidance (EXPERIMENTAL) +manufacturer = Bahamuto Dynamics +description = A missile guidance computer. Manually tune steering settings to craft's unique flight characteristics. Select a guidance mode. Select a target then enable guidance. Activate engines and stages manually. (EXPERIMENTAL) + +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.001 +dragModelType = default +maximum_drag = 0.02 +minimum_drag = 0.02 +angularDrag = .25 +crashTolerance = 60 +maxTemp = 3400 + +PhysicsSignificance = 1 + +MODULE +{ + name = BDModularGuidance + ForwardTransform = ForwardNegative + UpTransform = RightPositive +} + + +RESOURCE +{ + name = ElectricCharge + amount = 10 + maxAmount = 10 +} + +MODULE +{ + name = ModuleSAS + SASServiceLevel = 3 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/texture.png new file mode 100644 index 000000000..0e597b580 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/bammGuidance/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/Sounds/fire.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/Sounds/fire.ogg new file mode 100644 index 000000000..44be45cde Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/Sounds/fire.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/browninganm2.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/browninganm2.cfg new file mode 100644 index 000000000..9c6a921e9 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/browninganm2.cfg @@ -0,0 +1,92 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaBrowningAnm2 +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1.0 + + +// --- node definitions --- +node_attach = 0.0, -0.06105912, 0.05663621, 0, -1, 0, 1 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 950 +category = none +bdacategory = Guns +subcategory = 0 +bulkheadProfiles = srf +title = Browning Heavy Machine Gun (AN/M3) +manufacturer = Bahamuto Dynamics +description = An old fixed .50 cal machine gun 50cal ammo +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.04 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 60 +maxTemp = 3600 + +stagingIcon = SOLID_BOOSTER + +MODULE + { + name = ModuleWeapon + shortName = Browning AN/M3 + + fireTransformName = fireTransform + + hasDeployAnim = false + hasFireAnimation = false + + roundsPerMinute = 1150 + maxDeviation = 0.22 + maxEffectiveDistance = 2800 + maxTargetingRange = 4000 + + weaponType = ballistic + bulletType = 12.7mmBullet + ammoName = 50CalAmmo + + requestResourceAmount = 1 + shellScale = 0.463 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + projectileColor = 255, 50, 0, 160 //RGBA 0-255 + startColor = 255, 105, 25, 120 + fadeColor = true + tracerStartWidth = 0.18 + tracerEndWidth = 0.16 + tracerLength = 0 + tracerDeltaFactor = 2.75 + tracerInterval = 30 + nonTracerWidth = 0.035 + autoProxyTrackRange = 1200 + + fireSoundPath = BDArmory/Parts/browninganm2/Sounds/fire + overheatSoundPath = BDArmory/Parts/50CalTurret/sounds/turretOverheat + oneShotSound = true + + maxHeat = 3600 + heatPerShot = 115 + heatLoss = 825 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/model.mu new file mode 100644 index 000000000..3fb224191 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/smoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/smoke.png new file mode 100644 index 000000000..ceb6fa6e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/tex_browninganm2.png b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/tex_browninganm2.png new file mode 100644 index 000000000..a890b48cf Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/browninganm2/tex_browninganm2.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/clusterBomb.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/clusterBomb.cfg new file mode 100644 index 000000000..f61e11b6f --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/clusterBomb.cfg @@ -0,0 +1,98 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaClusterBomb +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.25, -0.1, 0, 1, 0, 0 +node_stack_top = 0.0, 0.25, 0, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 150 +category = none +bdacategory = Bombs +subcategory = 0 +bulkheadProfiles = srf +title = CBU-87 Cluster Bomb +manufacturer = Bahamuto Dynamics +description = This bomb splits open and deploys many small bomblets at a certain altitude. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.467 +dragModelType = none +maximum_drag = 0.03 +minimum_drag = 0.03 +angularDrag = 1 +crashTolerance = 5 +maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + shortName = CBU-87 + + thrust = 0 //KN thrust during boost phase + cruiseThrust = 0 //thrust during cruise phase + + guidanceActive = false + + decoupleSpeed = 2 + deployAnimationName = deploy + deployedDrag = 0.03 + deployTime = 0.2 + + explModelPath = BDArmory/Models/explosion/explosion + + useSimpleDrag = true + simpleCoD = 0,0,-2 + simpleStableTorque = 5 + rndAngVel = 0.7 + + missileType = bomb + homingType = none + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + } + + MODULE + { + name = BDExplosivePart + tntMass = 15 + } + + MODULE + { + name = ClusterBomb + + deployAltitude = 700 + deployDelay = 2.5 + submunitionMaxSpeed = 20 + swapCollidersOnDeploy = true + + subExplModelPath = BDArmory/Models/explosion/explosion + subExplSoundPath = BDArmory/Sounds/subExplode + } + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/model.mu new file mode 100644 index 000000000..215dbcd2f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/texture.png new file mode 100644 index 000000000..1e498dffd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/clusterBomb/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/chaffDispenser.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/chaffDispenser.cfg new file mode 100644 index 000000000..cca9bbc18 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/chaffDispenser.cfg @@ -0,0 +1,69 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaChaffPod +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.11, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Countermeasures +subcategory = 0 +bulkheadProfiles = srf +title = Chaff Dispenser +manufacturer = Bahamuto Dynamics +description = Drops chaff for confusing or breaking radar locks. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.001 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +MODEL +{ + model = BDArmory/Parts/cmDropper/model + texture = tex_cmDispenser, BDArmory/Parts/cmDropper/tex_chaffDispenser +} + + +MODULE +{ + name = CMDropper + ejectTransformName = cmTransform + countermeasureType = chaff + ejectVelocity = 5 +} + +RESOURCE +{ + name = CMChaff + amount = 42 + maxAmount = 42 +} +DRAG_CUBE +{ + cube = Default,0.06035,0.47415,0.1406,0.06035,0.47415,0.1406,0.06429,0.48925,0.1149,0.06429,0.42815,0.2935,0.05487,0.4389,0.1835,0.05487,0.4394,0.1835, 0,-0.1847,3.198E-08, 0.2372,0.2509,0.2774 +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/flareDispenser.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/flareDispenser.cfg new file mode 100644 index 000000000..d64185f89 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/flareDispenser.cfg @@ -0,0 +1,62 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaCmPod +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.11, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Countermeasures +subcategory = 0 +bulkheadProfiles = srf +title = Flare Dispenser +manufacturer = Bahamuto Dynamics +description = Drops flares for confusing heat-seeking missiles. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.001 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + + +MODULE +{ + name = CMDropper + countermeasureType = flare + ejectVelocity = 40 +} + +RESOURCE +{ + name = CMFlare + amount = 42 + maxAmount = 42 +} +DRAG_CUBE +{ + cube = Default,0.06035,0.47415,0.1406,0.06035,0.47415,0.1406,0.06429,0.48925,0.1149,0.06429,0.42815,0.2935,0.05487,0.4389,0.1835,0.05487,0.4394,0.1835, 0,-0.1847,3.198E-08, 0.2372,0.2509,0.2774 +} +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/model.mu new file mode 100644 index 000000000..406e7b8e4 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/tex_chaffDispenser.png b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/tex_chaffDispenser.png new file mode 100644 index 000000000..add889632 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/tex_chaffDispenser.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/tex_cmDispenser.png b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/tex_cmDispenser.png new file mode 100644 index 000000000..581506940 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/cmDropper/tex_cmDispenser.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/ecmj131.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/ecmj131.cfg new file mode 100644 index 000000000..a016241b9 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/ecmj131.cfg @@ -0,0 +1,65 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaECMJammer +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.2892764, -0.1571858, 0, 1, 0, 0 +node_stack_top = 0.0, 0.2892764, -0.1, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Countermeasures +subcategory = 0 +bulkheadProfiles = srf +title = AN/ALQ-131 ECM Jammer +manufacturer = Bahamuto Dynamics +description = This electronic device makes it harder for radars to lock onto your vehicle, and increases your chances of breaking the lock. It drastically increases your detectability when turned on, though. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.3 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + + +MODULE +{ + name = ModuleECMJammer + + // Jammer capabilities: + alwaysOn = false // can be enabled/disabled, or is always on + // Set this to true for "stealth" jammers that are integrated into Cockpits and serve + // to reduce only the radar cross section, but without providing another jamming effect! + + resourceDrain = 5 // EC/sec. Set this higher for more capabale jammers. + + jammerStrength = 1200 // this is a factor (in relation to a vessels base radar cross section) how much the crafts DETECTABILITY is INCREASED(!) when the jammer is active + + lockBreaker = true // true: jammer serves to break radar locks (default: true) + lockBreakerStrength = 500 // factor (in relation to a vessels base radar cross section) how strong the lockbreaking effect is + + rcsReduction = false // jammer reduces a crafts radar cross section, simulating 2nd generation stealth (radar obsorbent coating) + rcsReductionFactor = 0 // factor for radar cross section: from 0 (craft is invisible) to 1 (no effect) +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/model.mu new file mode 100644 index 000000000..7ec35cb35 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/tex_ecmj131.png b/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/tex_ecmj131.png new file mode 100644 index 000000000..d3f77f946 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/ecmJammer/tex_ecmj131.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/gau8.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/gau8.cfg new file mode 100644 index 000000000..41d4e16e0 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/gau8.cfg @@ -0,0 +1,105 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaGau-8 + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 0.78 + + + // --- node definitions --- + node_attach = 0, 0.3092, 1.88, 0, 1, 0, 0 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Guns + subcategory = 0 + bulkheadProfiles = srf + title = GAU-8 30x173mm Cannon + manufacturer = Bahamuto Dynamics + description = A 7 barrel 30mm rotary cannon. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 0,1,0,0,1 + + // --- standard part parameters --- + mass = 0.55 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 60 + maxTemp = 3600 + + stagingIcon = SOLID_BOOSTER + + MODULE + { + name = ModuleWeapon + shortName = GAU-8 + + fireTransformName = fireTransform + + hasDeployAnim = false + + hasFireAnimation = true + fireAnimName = fireAnim + spinDownAnimation = true + + roundsPerMinute = 3900 + maxDeviation = 0.45 + maxEffectiveDistance = 4000 + maxTargetingRange = 5000 + + weaponType = ballistic + ammoName = 30x173Ammo + bulletType = 30x173HEBullet + + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + useRippleFire = false + + projectileColor = 255, 70, 0, 128//RGBA 0-255 + startColor = 255, 90, 0, 32 + fadeColor = true + + tracerStartWidth = 0.10 + tracerEndWidth = 0.10 + tracerLength = 0 + tracerDeltaFactor = 2.75 + tracerInterval = 3 + nonTracerWidth = 0.035 + + maxHeat = 3600 + heatPerShot = 56 + heatLoss = 740 + + fireSoundPath = BDArmory/Parts/gau-8/sounds/GAU8Cannon + overheatSoundPath = BDArmory/Parts/gau-8/sounds/GAU8End + oneShotSound = false + + //explosion + airDetonation = false + airDetonationTiming = false + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode + + + } + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/model.mu new file mode 100644 index 000000000..58640b978 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/smoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/smoke.png new file mode 100644 index 000000000..ceb6fa6e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/sounds/GAU8Cannon.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/sounds/GAU8Cannon.ogg new file mode 100644 index 000000000..1b4a98b38 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/sounds/GAU8Cannon.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/sounds/GAU8End.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/sounds/GAU8End.ogg new file mode 100644 index 000000000..dd6c93554 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/sounds/GAU8End.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/texture.png new file mode 100644 index 000000000..8c54a52b2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/gau-8/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/Texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/Texture.png new file mode 100644 index 000000000..593cf4b36 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/Texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/goalkeeper.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/goalkeeper.cfg new file mode 100644 index 000000000..407396c03 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/goalkeeper.cfg @@ -0,0 +1,225 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaGoalKeeper + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1.134 + + + // --- node definitions --- + node_attach = 0.0, -0.7993, 0, 0, -1, 0, 0 + node_stack_bottom = 0.0, -0.7993, 0, 0, -1, 0, 2 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Gun turrets + subcategory = 0 + bulkheadProfiles = srf + title = Goalkeeper CIWS + manufacturer = Bahamuto Dynamics + description = A 7 barrel 30mm rotary cannon with full swivel range. The 30mm high explosive rounds self detonate at the set distance, but this weapon does not feature automatic fuse timing. It has its own detection & tracking radar, though that is only effective at close range and does not replace a proper volumen serach radar. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 4 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 50 + maxTemp = 3600 + + stagingIcon = SOLID_BOOSTER + + + + MODULE + { + name = ModuleTurret + turretID = 0 + + pitchTransformName = gunPitch + yawTransformName = gunYaw + + pitchSpeedDPS = 80 + yawSpeedDPS = 80 + + maxPitch = 85 + minPitch = -15 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.365 + minAudioPitch = 0.255 + maxVolume = 0.55 + } + + MODULE + { + name = ModuleWeapon + turretID = 0 + + fireTransformName = fireTransform + + hasDeployAnim = false + + hasFireAnimation = true + fireAnimName = fireAnimation2 + spinDownAnimation = true + + roundsPerMinute = 4200 + maxDeviation = 0.50 + maxEffectiveDistance = 4000 + maxTargetingRange = 5000 + + ammoName = 30x173Ammo + bulletType = 30x173HEBullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + weaponType = ballistic + + projectileColor = 255, 20, 0, 160//RGBA 0-255 + startColor = 255, 30, 0, 24 + fadeColor = true + + tracerStartWidth = 0.18 + tracerEndWidth = 0.18 + tracerLength = 0 + tracerDeltaFactor = 2.75 + tracerInterval = 2 + nonTracerWidth = 0.065 + + maxHeat = 3600 + heatPerShot = 36 + heatLoss = 900 + + shellScale = 0.76 + + fireSoundPath = BDArmory/Parts/gau-8/sounds/GAU8Cannon + overheatSoundPath = BDArmory/Parts/gau-8/sounds/GAU8End + oneShotSound = false + + //explosion + airDetonation = true + airDetonationTiming = false + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode + + + } + + MODULE + { + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = Goalkeeper CIWS Radar // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 0 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = scanRotation + turretID = 1 // if needed + resourceDrain = 0.45 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = true // false: boresight scan radar + directionalFieldOfView = 90 // for omni and boresight + //boresightFOV = 10 // for boresight only + scanRotationSpeed = 240 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + //lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = true // locking/tracking targets (fire control) + canTrackWhileScan = true // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 350 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 120 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.1 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 2 0 //between 0 and 2 km the min cross section is 0, thus assured detection of everything + key = 5 5 //max targeting range of the weapon is 5km, detectable rcs is quite small + key = 10 20 //at twice the maxTargeting range a rcs of min 20 m^2 can be detected + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + key = 0.0 0 + key = 5 5 //for tracking locks the radar is highly sensitive + key = 10 40 //at twice the maxTargeting range the lockable rcs is quite large + } + + } + + MODULE + { + name = ModuleTurret + + turretID = 1 + + pitchTransformName = radarPitch + yawTransformName = radarYaw + + pitchSpeedDPS = 120 + yawSpeedDPS = 120 + + maxPitch = 80 + minPitch = -5 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + } + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/model.mu new file mode 100644 index 000000000..e0a92aeaa Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/smoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/smoke.png new file mode 100644 index 000000000..ceb6fa6e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/tex_goalkeeper.png b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/tex_goalkeeper.png new file mode 100644 index 000000000..ac714a84e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/goalkeeper/tex_goalkeeper.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar1.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar1.cfg new file mode 100644 index 000000000..5f09c95bb --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar1.cfg @@ -0,0 +1,137 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = scanLockRadar1 +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = radar1.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Radars +subcategory = 0 +bulkheadProfiles = srf +title = TWS Locking Radar +manufacturer = Bahamuto Dynamics +description = This unit has a medium range detection radar and a built-in target tracking radar. This radar is capable of locking targets, and will continue to scan while tracking the locked target (TWS - Track While Scan). It is optimized for air search&track, and has difficulties detecting and tracking surface targets. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 1 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = TWS Locking Radar // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 0 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = rotationTransform + //turretID = 0 // if needed + resourceDrain = 0.85 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = true // false: boresight scan radar + directionalFieldOfView = 90 // for omni and boresight + //boresightFOV = 10 // for boresight only + scanRotationSpeed = 300 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + //lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = true // locking/tracking targets (fire control) + canTrackWhileScan = true // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 120 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 180 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.15 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 7 0 //between 0 and 7 km the min cross section is 0, thus assured detection of everything + key = 10 5 // + key = 20 15 //effective range 20km, can still detect relatively small rcs + key = 30 40 //max range 30km, but only for very large rcs + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + key = 0.0 0 + key = 7 5 //overall curve similar to detectionCurve, but needs bigger rcs to lock at comparable range + key = 10 7 + key = 20 20 + key = 30 50 + } +} + +MODULE +{ + name = ModuleTurret + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 120 + yawSpeedDPS = 120 + + maxPitch = 85 + minPitch = -8 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar1.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar1.mu new file mode 100644 index 000000000..2adab1e3a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar1.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar2.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar2.cfg new file mode 100644 index 000000000..35ed5cd74 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar2.cfg @@ -0,0 +1,124 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = scanLargeRadar +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = radar2.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Radars +subcategory = 0 +bulkheadProfiles = srf +title = Large Detection Radar +manufacturer = Bahamuto Dynamics +description = A large radar capable of detecting objects from a long distance. This radar does NOT have the capability of tracking or locking targets. It is optimized for air search, and has difficulties detecting surface targets. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 1.45 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +MODEL +{ + model = BDArmory/Parts/groundRadar/radar2 + texture = texture, BDArmory/Parts/groundRadar/tex_detectionRadar +} + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = Large Detection Radar // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 5 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = rotationTransform + //turretID = 0 // if needed + resourceDrain = 0.75 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = true // false: boresight scan radar + directionalFieldOfView = 90 // for omni and boresight + //boresightFOV = 10 // for boresight only + scanRotationSpeed = 110 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + //lockRotationAngle = 4 + showDirectionWhileScan = false // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + //maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = false // locking/tracking targets (fire control) + canTrackWhileScan = false // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 50 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 180 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.2 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 10 0 //between 0 and 10 km the min cross section is 0, thus assured detection of everything + key = 11 5 // + key = 20 10 //effective range 20km, can still detect relatively small rcs + key = 30 20 + key = 40 30 //max range 40km, but only for very large rcs + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + + //no locking capabilities + } + +} + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar2.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar2.mu new file mode 100644 index 000000000..42b00f057 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/radar2.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/tex_detectionRadar.png b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/tex_detectionRadar.png new file mode 100644 index 000000000..c55e20166 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/tex_detectionRadar.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/tex_lockingTurret.png b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/tex_lockingTurret.png new file mode 100644 index 000000000..6a91edc12 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/groundRadar/tex_lockingTurret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Launcher.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Launcher.cfg new file mode 100644 index 000000000..73c1372cf --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Launcher.cfg @@ -0,0 +1,71 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaH70Launcher +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1.2 + + +// --- node definitions --- +node_attach = 0.0, 0.1917292, 0, 0, 1, 0, 0 +node_stack_top = 0.0, 0.1917292, 0, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 650 +category = none +bdacategory = Rocket pods +subcategory = 0 +bulkheadProfiles = srf +title = Hydra-70 Rocket Pod +manufacturer = Bahamuto Dynamics +description = Holds and fires 19 unguided Hydra-70 rockets. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.016 +dragModelType = default +maximum_drag = 0.01 +minimum_drag = 0.01 +angularDrag = 2 +crashTolerance = 37 +maxTemp = 3600 + + +MODULE +{ + name = RocketLauncher + shortName = Hydra70 + rocketType = Hydra70Rocket + rocketMass = 0.0122 + rocketModelPath = BDArmory/Parts/h70Launcher/h70Rocket/model + thrust = 6.2 + thrustTime = 1.1 + blastRadius = 15 + blastForce = 7 + blastHeat = 15 + rippleRPM = 650 + +} + +RESOURCE +{ + name = Hydra70Rocket + amount = 19 + maxAmount = 19 +} + + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/model.mu new file mode 100644 index 000000000..1ffc36f46 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/rocketTexture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/rocketTexture.png new file mode 100644 index 000000000..d9075829a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/rocketTexture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/srbsmoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/srbsmoke.png new file mode 100644 index 000000000..85af65b2e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/h70Rocket/srbsmoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/model.mu new file mode 100644 index 000000000..389c63493 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/texture.png new file mode 100644 index 000000000..2667c3154 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/h70Launcher/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/h70turret.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/h70turret.cfg new file mode 100644 index 000000000..84ffabf46 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/h70turret.cfg @@ -0,0 +1,114 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaH70Turret + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1.2 + + + // --- node definitions --- + node_attach = 0.0, -0.3417777, 0, 0, -1, 0, 0 + node_stack_bottom = 0.0, -0.3417777, 0, 0, -1, 0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 650 + category = none + bdacategory = Rocket turrets + subcategory = 0 + bulkheadProfiles = srf + title = Hydra-70 Rocket Turret + manufacturer = Bahamuto Dynamics + description = Turret pod that holds and fires 32 unguided Hydra-70 rockets. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.416 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 37 + maxTemp = 3600 + + + MODULE + { + name = RocketLauncher + shortName = Hydra70 Turret + rocketType = Hydra70Rocket + rocketMass = 0.0122 + rocketModelPath = BDArmory/Parts/h70Launcher/h70Rocket/model + thrust = 6.2 + thrustTime = 1.1 + blastRadius = 15 + blastForce = 7 + blastHeat = 15 + rippleRPM = 650 + + thrustDeviation = 0.10 + + deployAnimationName = deployAnimation + } + + MODULE + { + name = ModuleTurret + + turretID = 0 + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 125 + yawSpeedDPS = 125 + + maxPitch = 35 + minPitch = -30 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.55 + minAudioPitch = 0.05 + maxVolume = .75 + } + + MODULE + { + name = BDALookConstraintUp + + targetName = pistonTransform + rotatorsName = cylinderTransform + } + + MODULE + { + name = BDALookConstraintUp + + targetName = cylinderTransform + rotatorsName = pistonTransform + } + + RESOURCE + { + name = Hydra70Rocket + amount = 32 + maxAmount = 32 + } + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/model.mu new file mode 100644 index 000000000..bb7019f2c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/tex_h70turret.png b/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/tex_h70turret.png new file mode 100644 index 000000000..61a71d01c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/h70turret/tex_h70turret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/harm/harm.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/harm/harm.cfg new file mode 100644 index 000000000..c3eef3dda --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/harm/harm.cfg @@ -0,0 +1,107 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaHarm + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.1262102, -0.6883147, 0, 1, 0, 0 + node_stack_top = 0.0, 0.1262102, -0.4, 0, 1, 0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 568 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = AGM-88 HARM Missile + manufacturer = Bahamuto Dynamics + description = High-speed anti-radiation missile. This missile will home in on radar sources detected by the Radar Warning Receiver. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.355 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE +{ + name = MissileLauncher + shortName = HARM + + thrust = 60 + cruiseThrust = 15 + dropTime = 0.5 + boostTime = 2.5 + cruiseTime = 60 + + guidanceActive = true + maxTurnRateDPS = 35 + + CruiseSpeed = 633.33 + + DetonationDistance = 0 + + decoupleSpeed = 5 + decoupleForward = false + + audioClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + + boostTransformName = boostTransform + boostExhaustTransformName = boostTransform + optimumAirspeed = 633.33 + + homingType = AGM + targetingType = antirad + terminalManeuvering = false + terminalGuidanceType = antirad + terminalGuidanceDistance = 30000 + + maxOffBoresight = 90 + lockedSensorFOV = 7 + + maxAoA = 40 + + aero = true + liftArea = 0.003 + steerMult = 8 + maxTorque = 55 + maxAoA = 40 + agmDescentRatio = 1.25 + + minStaticLaunchRange = 800 + maxStaticLaunchRange = 30000 + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false +} + MODULE + { + name = BDExplosivePart + tntMass = 70 + } + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/harm/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/harm/model.mu new file mode 100644 index 000000000..f1d780e62 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/harm/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/harm/tex_harm.png b/BDArmory/Distribution/GameData/BDArmory/Parts/harm/tex_harm.png new file mode 100644 index 000000000..4f497fd38 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/harm/tex_harm.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/hekv1.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/hekv1.cfg new file mode 100644 index 000000000..c140792f2 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/hekv1.cfg @@ -0,0 +1,92 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaHEKV1 +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.1232686, -0.3764487, 0, 1, 0, 0 +node_stack_top = 0.0, 0.1232686, 0.0, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 4000 +category = none +bdacategory = Missiles +subcategory = 0 +bulkheadProfiles = srf +title = HE-KV-1 Missile +manufacturer = Bahamuto Dynamics +description = The HE-KV-1 (High explosive kill vehicle) is a radar-guided homing missile that uses reaction control thrusters and thrust vectoring to maneuver. This means it is capable of steering towards targets in a vacuum. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.14 +dragModelType = default +maximum_drag = 0.01 +minimum_drag = 0.01 +angularDrag = 2 +crashTolerance = 5 +maxTemp = 3600 + + +MODULE +{ + name = MissileLauncher + shortName = HEKV + + thrust = 12 + cruiseThrust = 0 + dropTime = 1 + boostTime = 42 + cruiseTime = 0 + + maxTurnRateDPS = 25 //degrees per second + + decoupleSpeed = 5 + decoupleForward = true + + hasRCS = true + rcsThrust = 20 + + audioClipPath = BDArmory/Sounds/jet + guidanceActive = true //missile has guidanceActive + homingType = RCS + targetingType = radar + missileType = missile + DetonationDistance = 1 + + activeRadarRange = 40000 + maxOffBoresight = 360 + lockedSensorFOV = 15 + + radarLOAL = true + + minStaticLaunchRange = 500 + maxStaticLaunchRange = 100000 + + engageAir = true + engageMissile = true + engageGround = false + engageSLW = false +} + +MODULE +{ + name = BDExplosivePart + tntMass = 120 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/model.mu new file mode 100644 index 000000000..084acdace Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/texture.png new file mode 100644 index 000000000..859f39dc7 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hekv1/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/hellfireMissile.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/hellfireMissile.cfg new file mode 100644 index 000000000..c27f1f21a --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/hellfireMissile.cfg @@ -0,0 +1,102 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaAGM-114 + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.089, 0, 0, 1, 0, 0 + node_stack_top = 0.0, 0.089, 0, 0, 1, 0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 220 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = AGM-114R Hellfire II + manufacturer = Bahamuto Dynamics + description = Small, quick, laser guided homing missile. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.050 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + shortName = AGM-114R + + thrust = 10 //KN thrust during boost phase + cruiseThrust = 0 //thrust during cruise phase + dropTime = 0.4 //how many seconds after release until engine ignites + boostTime = 3.1 //seconds of boost phase + cruiseTime = 0 //seconds of cruise phase + + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 32 //degrees per second + + decoupleSpeed = 15 + decoupleForward = true + + + missileType = missile + homingType = AGM + targetingType = laser + maxOffBoresight = 180 + lockedSensorFOV = 7 + optimumAirspeed = 450 + DetonationDistance = 0.1 + agmDescentRatio = 1.1 + + maxAoA = 45 + + aero = true + liftArea = 0.0016 + steerMult = 0.9 + maxTorque = 15 + torqueRampUp = 50 + aeroSteerDamping = 5 + + minStaticLaunchRange = 500 + maxStaticLaunchRange = 8000 + + audioClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + + } + MODULE + { + name = BDExplosivePart + tntMass = 12 + } + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/hellfire_emp.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/hellfire_emp.cfg new file mode 100644 index 000000000..7ebb7a42a --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/hellfire_emp.cfg @@ -0,0 +1,109 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = HellfireEMP + module = Part + author = BahamutoD + + // --- asset parameters --- + MODEL + { + model = BDArmory/Parts/hellfireMissile/model + } + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.089, 0, 0, 1, 0, 0 + node_stack_top = 0.0, 0.089, 0, 0, 1, 0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 220 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = AGM-114R Hellfire II EMP + manufacturer = Bahamuto Dynamics + description = Small, quick, laser guided homing missile equipped with the latest miniaturized EMP warhead. While the pulse radius is small (50 meters), it is quite effective. The missile does minimal structural damage, but renders all electronic devices within it's blast radius inoperable. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.050 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + shortName = AGM-114R + + thrust = 10 //KN thrust during boost phase + cruiseThrust = 0 //thrust during cruise phase + dropTime = 0.4 //how many seconds after release until engine ignites + boostTime = 3.1 //seconds of boost phase + cruiseTime = 0 //seconds of cruise phase + DetonationDistance = 10 + + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 32 //degrees per second + + decoupleSpeed = 15 + decoupleForward = true + + + missileType = missile + homingType = AGM + targetingType = laser + maxOffBoresight = 180 + lockedSensorFOV = 7 + optimumAirspeed = 450 + DetonationDistance = 0.1 + agmDescentRatio = 1.1 + + maxAoA = 45 + + aero = true + liftArea = 0.0016 + steerMult = 0.9 + maxTorque = 15 + torqueRampUp = 50 + aeroSteerDamping = 5 + + minStaticLaunchRange = 500 + maxStaticLaunchRange = 8000 + + audioClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + } + MODULE + { + name = BDExplosivePart + tntMass = 0.01 + explModelPath = BDArmory/Models/EMPexplosion/EMPexplosionS + } + MODULE + { + name = ModuleEMP + proximity = 50 + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/model.mu new file mode 100644 index 000000000..94c8bc33f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/texture.png new file mode 100644 index 000000000..f6edfae6f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hellfireMissile/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/hiddenVulcan.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/hiddenVulcan.cfg new file mode 100644 index 000000000..44e0e2f5c --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/hiddenVulcan.cfg @@ -0,0 +1,98 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaHiddenVulcan +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1.0 + + +// --- node definitions --- +node_attach = 0.0, -0.01, 0, 0, -1, 0, 1 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 950 +category = none +bdacategory = Guns +subcategory = 0 +bulkheadProfiles = srf +title = Vulcan (Hidden) +manufacturer = Bahamuto Dynamics +description = A 6 barrel 20x102mm rotary cannon. 20x102Ammo +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.1 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 60 +maxTemp = 3600 + +stagingIcon = SOLID_BOOSTER + +MODULE +{ + name = ModuleWeapon + + fireTransformName = fireTransform + + hasDeployAnim = false + hasFireAnimation = false + + roundsPerMinute = 5500 + maxDeviation = 0.125 + maxEffectiveDistance = 2500 + maxTargetingRange = 5000 + + ammoName = 20x102Ammo + bulletType = 20x102mmHEBullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = false + bulletDrop = true + useRippleFire = false + + weaponType = ballistic + + projectileColor = 255, 60, 0, 128 //RGBA 0-255 + startColor = 255, 105, 0, 64 + fadeColor = true + + tracerStartWidth = 0.12 + tracerEndWidth = 0.12 + tracerLength = 0 + tracerDeltaFactor = 2.75 + tracerInterval = 3 + nonTracerWidth = 0.035 + + //oneShotWorldParticles = true + + maxHeat = 3600 + heatPerShot = 36 + heatLoss = 820 + + autoProxyTrackRange = 1200 + + fireSoundPath = BDArmory/Parts/20mmVulcan/sounds/VulcanCannon + overheatSoundPath = BDArmory/Parts/20mmVulcan/sounds/VulcanEnd + oneShotSound = false + + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/model.mu new file mode 100644 index 000000000..ae47c37a9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/smoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/smoke.png new file mode 100644 index 000000000..ceb6fa6e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/texture.png new file mode 100644 index 000000000..641b3b6c2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/hiddenVulcan/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/jdam.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/jdam.cfg new file mode 100644 index 000000000..c8d963035 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/jdam.cfg @@ -0,0 +1,86 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaJdamMk83 +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.1779008, 0.2834791, 0, 1, 0, 0 +node_stack_top = 0.0, 0.1779008, 0.2834791, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 200 +category = none +bdacategory = Bombs +subcategory = 0 +bulkheadProfiles = srf +title = Mk83 JDAM Bomb +manufacturer = Bahamuto Dynamics +description = 1000lb GPS-guided bomb. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.460 +dragModelType = default +maximum_drag = 0.02 +minimum_drag = 0.02 +angularDrag = 2 +crashTolerance = 5 +maxTemp = 3600 + +MODULE +{ + name = MissileLauncher + + shortName = Mk83 JDAM + + thrust = 0 //KN thrust during boost phase + cruiseThrust = 0 //thrust during cruise phase + dropTime = 1 //how many seconds after release until guidance begins + boostTime = 0 //seconds of boost phase + cruiseTime = 80 //seconds of cruise phase + guidanceActive = true + maxTurnRateDPS = 20 //degrees per second + + explModelPath = BDArmory/Models/explosion/explosionLarge + explSoundPath = BDArmory/Sounds/explode1 + + missileType = bomb + DetonationDistance = 0 + targetingType = gps + homingType = AGMBallistic + optimumAirspeed = 300 + + + aero = true + liftArea = 0.0009 + steerMult = .3 + maxTorque = 8 + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + +} +MODULE +{ + name = BDExplosivePart + tntMass = 300 +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/model.mu new file mode 100644 index 000000000..d39f1b666 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/tex_jdam.png b/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/tex_jdam.png new file mode 100644 index 000000000..94578318c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/jdamMk83/tex_jdam.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/m102.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/m102.cfg new file mode 100644 index 000000000..7be8a9dce --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/m102.cfg @@ -0,0 +1,120 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaM102Howitzer +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0, 0, 0.7742968, 0, 0, -1, 1 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 3500 +category = none +bdacategory = Gun turrets +subcategory = 0 +bulkheadProfiles = srf +title = M102 Howitzer (Radial) +manufacturer = Bahamuto Dynamics +description = A radially mounted 105mm gun. CannonShells +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 1 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 60 +maxTemp = 3600 + +stagingIcon = SOLID_BOOSTER + +MODULE +{ + name = ModuleTurret + + yawTransformName = aimRotate + pitchTransformName = aimPitch + + pitchSpeedDPS = 80 + yawSpeedDPS = 80 + + minPitch = -15 + maxPitch = 15 + yawRange = 30 + + smoothRotation = true + smoothMultiplier = 10 +} + +MODULE +{ + name = ModuleWeapon + shortName = M102 Howitzer + + fireTransformName = fireTransform + + hasDeployAnim = false + + hasFireAnimation = true + fireAnimName = fireAnim + spinDownAnimation = false + + roundsPerMinute = 13 + maxDeviation = 0.25 + maxTargetingRange = 8000 + maxEffectiveDistance = 8000 + + ammoName = CannonShells + bulletType = 105mmBullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + weaponType = ballistic + + projectileColor = 255, 90, 0, 128 + + tracerStartWidth = 0.27 + tracerEndWidth = 0.2 + tracerLength = 0 + tracerDeltaFactor = 3.75 + + maxHeat = 3600 + heatPerShot = 60 + heatLoss = 740 + + fireSoundPath = BDArmory/Parts/m1Abrams/sounds/shot + overheatSoundPath = BDArmory/Parts/50CalTurret/sounds/turretOverheat + oneShotSound = true + showReloadMeter = true + reloadAudioPath = BDArmory/Parts/m1Abrams/sounds/reload + +} + + + +RESOURCE +{ + name = CannonShells + amount = 20 + maxAmount = 20 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/model.mu new file mode 100644 index 000000000..f2e857ac0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/tex_m102.png b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/tex_m102.png new file mode 100644 index 000000000..823611d45 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m102Howitzer/tex_m102.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/m1Abrams.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/m1Abrams.cfg new file mode 100644 index 000000000..bb98e9744 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/m1Abrams.cfg @@ -0,0 +1,125 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaM1Abrams +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.178, 0, 0, -1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 3500 +category = none +bdacategory = Gun turrets +subcategory = 0 +bulkheadProfiles = srf +title = M1 Abrams Cannon +manufacturer = Bahamuto Dynamics +description = A 120mm cannon on an armored turret. CannonShells +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 2 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 125 +maxTemp = 3600 + +stagingIcon = SOLID_BOOSTER + +MODULE +{ + name = ModuleTurret + + yawTransformName = aimRotate + pitchTransformName = aimPitch + + pitchSpeedDPS = 60 + yawSpeedDPS = 40 + + minPitch = -4 + maxPitch = 27 + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.42 + minAudioPitch = 0.15 + maxVolume = 0.60 +} + +MODULE +{ + name = ModuleWeapon + + fireTransformName = fireTransform + + hasDeployAnim = false + + hasFireAnimation = true + fireAnimName = fireAnim + spinDownAnimation = false + + roundsPerMinute = 10 + maxDeviation = 0.2 + maxTargetingRange = 8000 + maxEffectiveDistance = 8000 + + ammoName = CannonShells + bulletType = 120mmBullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + weaponType = ballistic + + projectileColor = 255, 90, 0, 190 + + tracerStartWidth = 0.27 + tracerEndWidth = 0.20 + tracerLength = 0 + tracerDeltaFactor = 3.75 + tracerLuminance = 2 + + maxHeat = 3600 + heatPerShot = 60 + heatLoss = 740 + + fireSoundPath = BDArmory/Parts/m1Abrams/sounds/shot + overheatSoundPath = BDArmory/Parts/50CalTurret/sounds/turretOverheat + oneShotSound = true + showReloadMeter = true + reloadAudioPath = BDArmory/Parts/m1Abrams/sounds/reload + +} + + + + +RESOURCE +{ + name = CannonShells + amount = 20 + maxAmount = 20 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/model.mu new file mode 100644 index 000000000..072250c70 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/sounds/reload.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/sounds/reload.ogg new file mode 100644 index 000000000..acc0841ba Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/sounds/reload.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/sounds/shot.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/sounds/shot.ogg new file mode 100644 index 000000000..40bcd86d2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/sounds/shot.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/tex_abrams.png b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/tex_abrams.png new file mode 100644 index 000000000..13edb994a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m1Abrams/tex_abrams.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230loop.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230loop.ogg new file mode 100644 index 000000000..ec33fba37 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230loop.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230loopEnd.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230loopEnd.ogg new file mode 100644 index 000000000..4a6511eb5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230loopEnd.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230shot.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230shot.ogg new file mode 100644 index 000000000..aa677e1da Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/Sounds/m230shot.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/m230.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/m230.cfg new file mode 100644 index 000000000..12ed1a8f1 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/m230.cfg @@ -0,0 +1,156 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaM230ChainGun +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.06, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 950 +category = none +bdacategory = Gun turrets +subcategory = 0 +bulkheadProfiles = srf +title = M230 Chain Gun Turret +manufacturer = Bahamuto Dynamics +description = The M230 Chain Gun is a single-barrel automatic cannon firing 30x173 Ammo high explosive rounds. It is commonly used on attack helicopters. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.1 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 60 +maxTemp = 3600 + +stagingIcon = SOLID_BOOSTER + +MODULE +{ + name = ModuleTurret + + yawTransformName = aimRotate + pitchTransformName = aimPitch + + pitchSpeedDPS = 120 + yawSpeedDPS = 120 + + minPitch = -17 + maxPitch = 50 + yawRange = 270 + + smoothRotation = true + smoothMultiplier = 10 +} + +MODULE +{ + name = ModuleWeapon + + shortName = M230 + + fireTransformName = fireTransform + + hasDeployAnim = true + deployAnimName = deploy + hasFireAnimation = true + fireAnimName = fireAnim + spinDownAnimation = false + + roundsPerMinute = 625 + maxDeviation = 0.4 + maxEffectiveDistance = 2500 + maxTargetingRange = 5000 + + ammoName = 30x173Ammo + bulletType = 30x173HEBullet + requestResourceAmount = 1 + shellScale = 0.66 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + weaponType = ballistic + + projectileColor = 255, 90, 0, 128 //RGBA 0-255 + startColor = 255, 105, 0, 90 + tracerStartWidth = 0.16 + tracerEndWidth = 0.16 + tracerLength = 0 + + oneShotWorldParticles = true + + maxHeat = 3600 + heatPerShot = 166 + heatLoss = 820 + + + fireSoundPath = BDArmory/Parts/m230ChainGun/Sounds/m230loop + overheatSoundPath = BDArmory/Parts/m230ChainGun/Sounds/m230loopEnd + oneShotSound = false + + //explosion + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode + +} + +MODULE +{ + name = BDALookConstraintUp + targetName = pitchPiston + rotatorsName = pitchCylinder +} + +MODULE +{ + name = BDALookConstraintUp + targetName = pitchCylinder + rotatorsName = pitchPiston +} + + +MODULE +{ + name = BDALookConstraintUp + targetName = springTarget + rotatorsName = springHolder +} + +MODULE +{ + name = BDALookConstraintUp + targetName = springHolder + rotatorsName = springTarget +} + + +MODULE +{ + name = BDAScaleByDistance + transformToScaleName = spring + scaleFactor = 0,0,2.62 + distanceTransformName = springTarget +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/model.mu new file mode 100644 index 000000000..ec4bd1b01 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/muzzle.png new file mode 100644 index 000000000..865a9e937 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/smoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/smoke.png new file mode 100644 index 000000000..ceb6fa6e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/texture.png new file mode 100644 index 000000000..7b20904e9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/m230ChainGun/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/maverickMissile.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/maverickMissile.cfg new file mode 100644 index 000000000..43cb723c4 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/maverickMissile.cfg @@ -0,0 +1,94 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaAGM-65 + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.15, -0.5, 0, 1, 0, 0 + node_stack_top = 0.0, 0.15, -0.1, 0, 1, 0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 400 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = AGM-65 Maverick Missile + manufacturer = Bahamuto Dynamics + description = Medium yield laser guided air-to-ground missile. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.27 + dragModelType = default + maximum_drag = 0.02 + minimum_drag = 0.02 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + shortName = AGM-65 + + thrust = 44 //KN thrust during boost phase + cruiseThrust = 9.6 //thrust during cruise phase + dropTime = 0 //how many seconds after release until engine ignites + boostTime = 0.575 //seconds of boost phase + cruiseTime = 3.495 //seconds of cruise phase + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 9 //degrees per second + + audioClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + boostExhaustTransformName = boostTransform + boostTransformName = boostTransform + + homingType = AGM + agmDescentRatio = 1.85 + optimumAirspeed = 350 + + missileType = missile + targetingType = laser + DetonationDistance = 0 + + aero = true + liftArea = 0.0048 + steerMult = .75 + maxTorque = 15 + + minStaticLaunchRange = 800 + maxStaticLaunchRange = 5500 + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + + } + MODULE + { + name = BDExplosivePart + tntMass = 85.5 + } + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/model.mu new file mode 100644 index 000000000..ba137058b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/texture.png new file mode 100644 index 000000000..5f6b6b73a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/maverick/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/missileTurret.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/missileTurret.cfg new file mode 100644 index 000000000..1a128a05b --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/missileTurret.cfg @@ -0,0 +1,183 @@ +PART +{ + // Kerbal Space Program - Part Config + + // --- general parameters --- + name = missileTurretTest + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, -0.4362216, 0, 0, -1, 0, 0 + node_stack_bottom = 0.0, -0.4362216, 0, 0, -1, 0, 1 + node_stack_missile1 = -0.7069921, 0.439827, 0.8738811, 0, 1, 0, 0 + node_stack_missile2 = 0.7069921, 0.439827, 0.8738811, 0, 1, 0, 0 + node_stack_missile3 = -1.289303, 0.439827, 0.8738811, 0, 1, 0, 0 + node_stack_missile4 = 1.289303, 0.439827, 0.8738811, 0, 1, 0, 0 + node_stack_missile5 = -0.7069921, 0.1269047, 0.8738811, 0, -1, 0, 0 + node_stack_missile6 = 0.7069921, 0.1269047, 0.8738811, 0, -1, 0, 0 + node_stack_missile7 = -1.289303, 0.1269047, 0.8738811, 0, -1, 0, 0 + node_stack_missile8 = 1.289303, 0.1269047, 0.8738811, 0, -1, 0, 0 + stackSymmetry = 1 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Missile turrets + subcategory = 0 + bulkheadProfiles = srf + title = Jernas Missile Turret + manufacturer = Bahamuto Dynamics + description = A turret capable of holding and firing up to 8 small to medium sized missiles. Comes with an integrated detection and tracking radar. Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,1,0,1 + + // --- standard part parameters --- + mass = 0.75 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 60 + maxTemp = 3600 + + + MODULE + { + name = ModuleTurret + + turretID = 0 + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 55 + yawSpeedDPS = 55 + + maxPitch = 75 + minPitch = -8 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.565 + minAudioPitch = 0.15 + } + + MODULE + { + name = MissileTurret + + turretID = 0 + + finalTransformName = pitchTransform + + disableRadarYaw = true + } + + MODULE + { + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = Jernas Radar // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 0 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = scanRotation + turretID = 1 // if needed + resourceDrain = 0.5 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = true // false: boresight scan radar + directionalFieldOfView = 90 // for omni and boresight + //boresightFOV = 10 // for boresight only + scanRotationSpeed = 190 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + //lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = true // locking/tracking targets (fire control) + canTrackWhileScan = true // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 300 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 220 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.1 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 5 0 //between 0 and 5 km the min cross section is 0, thus assured detection of everything + key = 10 10 // + key = 15 20 // + key = 20 25 // this radar is NOT very good at detection (limited range, needs large rcs) + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + key = 0.0 0 + key = 5 5 //for tracking locks the radar is highly sensitive + key = 10 7 //this radar is relatively good at locking/tracking + key = 15 15 // + key = 20 20 // this radar is NOT very good at detection (limited range, needs large rcs) + } + + } + + MODULE + { + name = ModuleTurret + + turretID = 1 + + pitchTransformName = radarPitch + yawTransformName = radarYaw + + pitchSpeedDPS = 125 + yawSpeedDPS = 125 + + maxPitch = 80 + minPitch = -1 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/model.mu new file mode 100644 index 000000000..39cf43409 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_detectionRadar.png b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_detectionRadar.png new file mode 100644 index 000000000..c55e20166 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_detectionRadar.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_lockingTurret.png b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_lockingTurret.png new file mode 100644 index 000000000..6a91edc12 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_lockingTurret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_missileTurret.png b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_missileTurret.png new file mode 100644 index 000000000..a7b3d6a17 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/missileTurret/tex_missileTurret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/mk82Bomb.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/mk82Bomb.cfg new file mode 100644 index 000000000..a21cb46a7 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/mk82Bomb.cfg @@ -0,0 +1,81 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaMk82Bomb +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.1365, -0.1287, 0, 1, 0, 0 +node_stack_top = 0.0, 0.1365, 0.15, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 50 +category = none +bdacategory = Bombs +subcategory = 0 +bulkheadProfiles = srf +title = Mk82 Bomb +manufacturer = Bahamuto Dynamics +description = 500lb unguided bomb. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.227 +dragModelType = default +maximum_drag = 0.02 +minimum_drag = 0.02 +angularDrag = 1 +crashTolerance = 5 +maxTemp = 3600 + +MODULE +{ + name = MissileLauncher + + shortName = Mk82 + + thrust = 0 //KN thrust during boost phase + cruiseThrust = 0 //thrust during cruise phase + dropTime = 3 //how many seconds after release until engine ignites + boostTime = 2.2 //seconds of boost phase + cruiseTime = 80 //seconds of cruise phase + guidanceActive = false //missile has guidanceActive + maxTurnRateDPS = 20 //degrees per second + + explModelPath = BDArmory/Models/explosion/explosionLarge + explSoundPath = BDArmory/Sounds/explode1 + + useSimpleDrag = true + simpleCoD = 0,0,-2 + simpleStableTorque = 5 + rndAngVel = 2 + + missileType = bomb + homingType = none + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false +} +MODULE +{ + name = BDExplosivePart + tntMass = 140 +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/model.mu new file mode 100644 index 000000000..91baf5ea6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/texture.png new file mode 100644 index 000000000..1de15ac92 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82Bomb/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/mk82BombBrake.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/mk82BombBrake.cfg new file mode 100644 index 000000000..d961605bc --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/mk82BombBrake.cfg @@ -0,0 +1,90 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaMk82BombBrake +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.1365, -0.1287, 0, 1, 0, 0 +node_stack_top = 0.0, 0.1365, 0.15, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 75 +category = none +bdacategory = Bombs +subcategory = 0 +bulkheadProfiles = srf +title = Mk82 SnakeEye Bomb +manufacturer = Bahamuto Dynamics +description = 500lb unguided bomb with airbrakes. Use for low altitude bombing. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.227 +dragModelType = default +maximum_drag = 0.02 +minimum_drag = 0.02 +angularDrag = 1 +crashTolerance = 5 +maxTemp = 3600 + + + +MODULE +{ + name = MissileLauncher + + shortName = Mk82 SnakeEye + + thrust = 0 //KN thrust during boost phase + cruiseThrust = 0 //thrust during cruise phase + + guidanceActive = false + blastRadius = 40 //meters + blastPower = 25 + + + decoupleSpeed = 2 + deployAnimationName = deploy + + deployedDrag = 0.15 + //deployedDrag = 0 + + deployTime = 0.55 + explModelPath = BDArmory/Models/explosion/explosionLarge + + useSimpleDrag = true + simpleCoD = 0,0,-2 + simpleStableTorque = 5 + rndAngVel = 2 + + missileType = bomb + homingType = none + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false +} + +MODULE +{ + name = BDExplosivePart + tntMass = 133.5 +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/model.mu new file mode 100644 index 000000000..77225f89d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/texture.png new file mode 100644 index 000000000..d991f1c15 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/mk82BombBrake/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/Sounds/oFireEnd.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/Sounds/oFireEnd.ogg new file mode 100644 index 000000000..32dd94de1 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/Sounds/oFireEnd.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/Sounds/oFiring.ogg b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/Sounds/oFiring.ogg new file mode 100644 index 000000000..349e5a5a4 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/Sounds/oFiring.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/model.mu new file mode 100644 index 000000000..2dde2e813 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/oMillennium.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/oMillennium.cfg new file mode 100644 index 000000000..f9be2b0b5 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/oMillennium.cfg @@ -0,0 +1,123 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaOMillennium + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, -0.6017585, 0, 0, -1, 0, 1 + + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 3500 + category = none + bdacategory = Gun turrets + subcategory = 0 + bulkheadProfiles = srf + title = Oerlikon Millennium Cannon + manufacturer = Bahamuto Dynamics + description = A turret that fires timed detonation explosive rounds. Suited for close-in air defense. A device at the muzzle end of the barrel measures the exact speed of each round as it is fired, and automatically sets the fuse to detonate the round as it approaches a pre-set distance from the target. Uses 30x173Ammo + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 0,1,0,0,1 + + // --- standard part parameters --- + mass = 2 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 125 + maxTemp = 3600 + + stagingIcon = SOLID_BOOSTER + + + MODULE + { + name = ModuleTurret + + yawTransformName = aimYaw + pitchTransformName = aimPitch + + pitchSpeedDPS = 120 + yawSpeedDPS = 120 + + minPitch = -4 + maxPitch = 75 + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.65 + minAudioPitch = 0.355 + maxVolume = 0.55 + } + + MODULE + { + name = ModuleWeapon + + shortName = Millennium Cannon + + fireTransformName = fireTransform + + oneShotWorldParticles = true + + hasDeployAnim = false + hasFireAnimation = true + fireAnimName = fireAnimation + spinDownAnimation = false + + roundsPerMinute = 850 + maxDeviation = 0.47 + maxTargetingRange = 3800 + + airDetonation = true + maxEffectiveDistance = 3800 + + weaponType = ballistic + ammoName = 30x173Ammo + bulletType = 30x173HEBullet + requestResourceAmount = 1 + + hasRecoil = true + onlyFireInRange = true + bulletDrop = true + + projectileColor = 255, 110, 0, 128 + + tracerStartWidth = 0.22 + tracerEndWidth = 0.18 + tracerLength = 0 + + maxHeat = 3600 + heatPerShot = 200 + heatLoss = 740 + + fireSoundPath = BDArmory/Parts/oMillennium/Sounds/oFiring + overheatSoundPath = BDArmory/Parts/oMillennium/Sounds/oFireEnd + oneShotSound = false + showReloadMeter = false + explModelPath = BDArmory/Models/explosion/30mmExplosion + explSoundPath = BDArmory/Sounds/subExplode + + } + + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/smoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/smoke.png new file mode 100644 index 000000000..ceb6fa6e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/smoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/srbsmoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/srbsmoke.png new file mode 100644 index 000000000..85af65b2e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/srbsmoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/texture.png new file mode 100644 index 000000000..3396eba87 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/oMillennium/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/model.mu new file mode 100644 index 000000000..d25f455a6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/pac3.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/pac3.cfg new file mode 100644 index 000000000..c69a7af2e --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/pac3.cfg @@ -0,0 +1,94 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaPac-3 + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.1343161, 0, 0, 1, 0, 0 + node_stack_top = 0.0, 0.1343161, 0, 0, 1, 0, 0 + node_stack_bottom = 0, 0, -2.900545, 0, 0, -1, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 4000 + bdacategory = Missiles + category = none + subcategory = 0 + bulkheadProfiles = srf + title = MIM-104F PATRIOT PAC-3 + manufacturer = Bahamuto Dynamics + description = Medium range, high speed, radar-guided surface to air missile. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.312 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + shortName = PAC-3 + + thrust = 80 //KN thrust during boost phase + cruiseThrust = 59 //thrust during cruise phase + dropTime = 0 //how many seconds after release until engine ignites + boostTime = 6 //seconds of boost phase + cruiseTime = 30 //seconds of cruise phase + guidanceActive = true //missile has guidanceActive + + decoupleSpeed = 10 + decoupleForward = true + + audioClipPath = BDArmory/Sounds/rocketLoop + + exhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + + optimumAirspeed = 1250 + + aero = true + liftArea = 0.005 + steerMult = 6 + maxTorque = 90 + + missileType = missile + homingType = aam + targetingType = radar + activeRadarRange = 15000 + maxOffBoresight = 180 + lockedSensorFOV = 7 + + minStaticLaunchRange = 2000 + maxStaticLaunchRange = 30000 + + engageAir = true + engageMissile = false + engageGround = true + engageSLW = false + } + + MODULE + { + name = BDExplosivePart + tntMass = 73 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/texture.png new file mode 100644 index 000000000..4a663ce5f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/pac-3/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/model.mu new file mode 100644 index 000000000..6a6850702 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/patriotLauncher.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/patriotLauncher.cfg new file mode 100644 index 000000000..c1f22a0cf --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/patriotLauncher.cfg @@ -0,0 +1,125 @@ +PART +{ + // Kerbal Space Program - Part Config + + // --- general parameters --- + name = patriotLauncherTurret + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, -1.592427, -1.046865, 0, -1, 0, 0 + node_stack_bottom = 0.0, -1.592427, -1.046865, 0, -1, 0, 1 + + node_stack_missile1 = 0.8587526, 0.7144908, -2.094282, 0, 0, 1, 0 + node_stack_missile4 = 0.8587526, -0.3667703, -2.094282, 0, 0, 1, 0 + node_stack_missile6 = 0.8587526, 1.154978, -2.094282, 0, 0, 1, 0 + node_stack_missile16 = 0.8587526, 0.07371697, -2.094282, 0, 0, 1, 0 + + + node_stack_missile2 = 0.4130825, 0.7144908, -2.094282, 0, 0, 1, 0 + node_stack_missile3 = 0.4130825, 1.154978, -2.094282, 0, 0, 1, 0 + node_stack_missile14 = 0.4130825, 0.07371697, -2.094282, 0, 0, 1, 0 + node_stack_missile15 = 0.4130825, -0.3667703, -2.094282, 0, 0, 1, 0 + + node_stack_missile5 = -0.4201337, 1.154978, -2.094282, 0, 0, 1, 0 + node_stack_missile7 = -0.4201337, 0.07371697, -2.094282, 0, 0, 1, 0 + node_stack_missile12 = -0.4201337, 0.7144908, -2.094282, 0, 0, 1, 0 + node_stack_missile13 = -0.4201337, -0.3667703, -2.094282, 0, 0, 1, 0 + + node_stack_missile9 = -0.8658038, 0.07371697, -2.094282, 0, 0, 1, 0 + node_stack_missile10 = -0.8658038, 1.154978, -2.094282, 0, 0, 1, 0 + node_stack_missile11 = -0.8658038, 0.7144908, -2.094282, 0, 0, 1, 0 + node_stack_missile8 = -0.8658038, -0.3667703, -2.094282, 0, 0, 1, 0 + + + + + stackSymmetry = 1 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Missile turrets + subcategory = 0 + bulkheadProfiles = srf + title = Patriot Launcher Turret + manufacturer = Bahamuto Dynamics + description = A turret capable of holding and firing up to 16 PAC-3 missiles (4 per cannister). Warranty void if anything except missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,1,0,1 + + // --- standard part parameters --- + mass = 1.75 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 60 + maxTemp = 3600 + + + MODULE + { + name = ModuleTurret + + turretID = 0 + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 20 + yawSpeedDPS = 20 + + maxPitch = 65 + minPitch = 0 + + yawRange = 360 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.42 + minAudioPitch = 0.15 + } + + MODULE + { + name = MissileTurret + + turretID = 0 + + finalTransformName = pitchTransform + deployAnimationName = deployAnimation + deployAnimationSpeed = 1 + railLength = 6.85 + firePauseTime = 1 + } + + MODULE + { + name = BDALookConstraintUp + + targetName = pistonTransform + rotatorsName = cylinderTransform + } + + MODULE + { + name = BDALookConstraintUp + + targetName = cylinderTransform + rotatorsName = pistonTransform + } + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/tex_patLauncher.png b/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/tex_patLauncher.png new file mode 100644 index 000000000..e8d2ab564 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/patriotLauncher/tex_patLauncher.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/model.mu new file mode 100644 index 000000000..1e93ec958 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/radarDataReceiver.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/radarDataReceiver.cfg new file mode 100644 index 000000000..fe2084cae --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/radarDataReceiver.cfg @@ -0,0 +1,114 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = radarDataReceiver +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Radars +subcategory = 0 +bulkheadProfiles = srf +title = Radar Data Receiver +manufacturer = Bahamuto Dynamics +description = A module that can display radar contacts via data-link and lock targets through a remote radar, but can not scan or lock by itself. Useful for a hidden missile battery. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.05 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +physicsSignificance = 1 + + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = Radar Data Receiver // if left empty part.title is used, but advised to set this to a nice printable text + //rwrThreatType = 0 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + //rotationTransformName = scanRotation + //turretID = 0 // if needed + resourceDrain = 0.25 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + //omnidirectional = true // false: boresight scan radar + //directionalFieldOfView = 90 // for ominidrectional only + //boresightFOV = 10 // for boresight only + //scanRotationSpeed = 240 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + //lockRotationAngle = 4 + //showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + //multiLockFOV = 30 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + //maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = false // scanning/detecting targets (volume search) + canLock = false // locking/tracking targets (fire control) + canTrackWhileScan = false // continue scanning while tracking a locked target + canRecieveRadarData = true // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + //minSignalThreshold = 350 // DEPRECATED, NO LONGER USED! use detection float curve! + //minLockedSignalThreshold = 120 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + //radarGroundClutterFactor = 0.1 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (very hard to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs aireal targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + + // nothing defined here as this radar does not support scanning on its own + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers completely ineffective!! + // Min cross section for locking should always be at least 1 m^2, even at range 0km! + // key = distance rcs + + // nothing defined here as this radar does not support locking + } +} + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/tex_dataReceiver.png b/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/tex_dataReceiver.png new file mode 100644 index 000000000..546aa9033 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/radarDataReceiver/tex_dataReceiver.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1.cfg new file mode 100644 index 000000000..b32dd3f6b --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1.cfg @@ -0,0 +1,111 @@ +PART +{ + name = bdRadome1 + module = Part + author = BahamutoD + rescaleFactor = 1 + node_stack_bottom01 = 0.0, -0.9382, 0.0, 0.0, -1.0, 0.0, 1 + //node_attach = 0, 0, -0.313, 0.0, 0.0, 1.0 + TechRequired = precisionEngineering + entryCost = 6200 + cost = 320 + category = none + bdacategory = Radars + subcategory = 0 + bulkheadProfiles = size1 + title = AN/APG-63V2 Radome + manufacturer = Bahamuto Dynamics + description = A forward facing, aerodynamically housed radar. It can scan and lock targets within a 120 degree field of view. It is optimized for air-to-air combat, and has difficulties locking surface targets. + attachRules = 1,0,1,1,0 + stackSymmetry = 2 + mass = 0.375 + dragModelType = default + maximum_drag = 0.1 + minimum_drag = 0.1 + angularDrag = .25 + crashTolerance = 40 + maxTemp = 2000 + fuelCrossFeed = True + thermalMassModifier = 6.0 + emissiveConstant = 0.95 + MODEL + { + model = BDArmory/Parts/radome125/radome1 + } + + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = AN/APG-63V2 Radome // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 1 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = scanRotation + //turretID = 0 // if needed + resourceDrain = 0.825 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = false // false: boresight scan radar + directionalFieldOfView = 120 // for omni and boresight + //boresightFOV = 10 // for boresight only + //scanRotationSpeed = 240 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + multiLockFOV = 40 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + maxLocks = 3 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = true // locking/tracking targets (fire control) + canTrackWhileScan = true // continue scanning while tracking a locked target + canRecieveRadarData = false // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 80 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 100 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.1 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 5 0 //between 0 and 5 km the min cross section is 0, thus assured detection of everything + key = 10 5 // + key = 20 15 // + key = 35 25 //maxrange of 35km + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + key = 0.0 0 + key = 5 5 // + key = 10 7 // + key = 20 20 // + key = 35 35 //maxrange of 35km + } +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1.mu new file mode 100644 index 000000000..ae3abc0a9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1inline.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1inline.cfg new file mode 100644 index 000000000..95c40a1d6 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1inline.cfg @@ -0,0 +1,112 @@ +PART +{ + name = bdRadome1inline + module = Part + author = BahamutoD + rescaleFactor = 1 + node_stack_bottom01 = 0.0, -0.6598, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_top = 0.0, 0.6598, 0.0, 0.0, 1.0, 0.0, 1 + node_attach = 0, 0, -0.625, 0.0, 0.0, 1.0 + TechRequired = precisionEngineering + entryCost = 6200 + cost = 320 + category = none + bdacategory = Radars + subcategory = 0 + bulkheadProfiles = size1 + title = AN/APG-63V2 Inline Radome + manufacturer = Bahamuto Dynamics + description = A forward facing, aerodynamically housed radar. It can scan and lock targets within a 120 degree field of view. Make sure the black markings are pointing forward. It is optimized for air-to-air combat, and has difficulties locking surface targets. + attachRules = 1,1,1,1,0 + stackSymmetry = 2 + mass = 0.375 + dragModelType = default + maximum_drag = 0.1 + minimum_drag = 0.1 + angularDrag = .25 + crashTolerance = 40 + maxTemp = 2000 + fuelCrossFeed = True + thermalMassModifier = 6.0 + emissiveConstant = 0.95 + MODEL + { + model = BDArmory/Parts/radome125/radome1inline + } + + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = AN/APG-63V2 Inline Radome // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 1 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = scanRotation + //turretID = 0 // if needed + resourceDrain = 0.825 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = false // false: boresight scan radar + directionalFieldOfView = 120 // for omni and boresight + //boresightFOV = 10 // for boresight only + //scanRotationSpeed = 240 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + multiLockFOV = 40 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + maxLocks = 3 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = true // locking/tracking targets (fire control) + canTrackWhileScan = true // continue scanning while tracking a locked target + canRecieveRadarData = false // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 80 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 100 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.1 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 5 0 //between 0 and 5 km the min cross section is 0, thus assured detection of everything + key = 10 5 // + key = 20 15 // + key = 35 25 //maxrange of 35km + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + key = 0.0 0 + key = 5 5 // + key = 10 7 // + key = 20 20 // + key = 35 35 //maxrange of 35km + } +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1inline.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1inline.mu new file mode 100644 index 000000000..8d64a3b35 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1inline.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1snub.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1snub.cfg new file mode 100644 index 000000000..7d0378c7d --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1snub.cfg @@ -0,0 +1,111 @@ +PART +{ + name = bdRadome1snub + module = Part + author = BahamutoD + rescaleFactor = 1 + node_stack_bottom01 = 0.0, -0.4816, 0.0, 0.0, -1.0, 0.0, 1 + //node_attach = 0, 0, -0.313, 0.0, 0.0, 1.0 + TechRequired = precisionEngineering + entryCost = 6200 + cost = 320 + category = none + bdacategory = Radars + subcategory = 0 + bulkheadProfiles = size1 + title = AN/APG-63V1 Radome + manufacturer = Bahamuto Dynamics + description = A forward facing, aerodynamically housed radar. It can scan and lock targets within a 120 degree field of view. This is a dedicated ground attack version with much better performance against ground targets, but reduced air-to-air capabilities. + attachRules = 1,0,1,1,0 + stackSymmetry = 2 + mass = 0.375 + dragModelType = default + maximum_drag = 0.1 + minimum_drag = 0.1 + angularDrag = .25 + crashTolerance = 40 + maxTemp = 2000 + fuelCrossFeed = True + thermalMassModifier = 6.0 + emissiveConstant = 0.95 + MODEL + { + model = BDArmory/Parts/radome125/radome1snub + } + + +MODULE +{ + name = ModuleRadar + + // -- Section: General Configuration -- + radarName = AN/APG-63V1 Radome // if left empty part.title is used, but advised to set this to a nice printable text + rwrThreatType = 1 // IMPORTANT, please set correctly: + // 0 = SAM site radar + // 1 = Fighter radar (airborne) + // 2 = AWACS radar (airborne) + // 3, 4 = ACTIVE MISSILE (DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING! + // 5 = Detection radar (ground/ship based) + // 6 = SONAR (ship/submarine based) + rotationTransformName = scanRotation + //turretID = 0 // if needed + resourceDrain = 0.75 // change to higher values for more capable radars, e.g AESA + + // -- Section: Capabilities -- + omnidirectional = false // false: boresight scan radar + directionalFieldOfView = 120 // for omni and boresight + //boresightFOV = 10 // for boresight only + //scanRotationSpeed = 240 // degress per second + //lockRotationSpeed = 120 // only relevant if canLock + lockRotationAngle = 4 + showDirectionWhileScan = true // can show target direction on radar screen. False: radar echos displayed as block only (no direction) + multiLockFOV = 40 // only relevant if canLock + //lockAttemptFOV = 2 // only relevant if canLock + maxLocks = 1 //how many targets can be locked/tracked simultaneously. only relevant if canLock + + canScan = true // scanning/detecting targets (volume search) + canLock = true // locking/tracking targets (fire control) + canTrackWhileScan = true // continue scanning while tracking a locked target + canRecieveRadarData = false // can work as passive data receiver (NOTE THE SPELLING! [SIC]) + + minSignalThreshold = 80 // DEPRECATED, NO LONGER USED! use detection float curve! + minLockedSignalThreshold = 100 // DEPRECATED, NO LONGER USED! use locktrack float curve! + + radarGroundClutterFactor = 0.4 // how much is the radar efficiency reduced to by ground clutter/look-down? + // 0.0 = reduced to 0% (=IMPOSSIBLE to detect ground targets) + // 1.0 = fully efficient (no difference between air & ground targets) + // default if unset: 0.25 + // Ground targets, especially ships, already have a massively larger RCS than fighters, hence + // any ground clutter factor >0.25 is to be considered very good, making an efficient surface/horizon search radar. + // values >1.0 are possible, meaning the radar is MORE efficient during look down than vs air targets. + + radarDetectionCurve + { + // floatcurve to define at what range (km) which minimum cross section (m^2) can be detected. + // this defines both min/max range of the radar, and sensitivity/efficiency + // it is recommended to define an "assured detection range", at which all craft are detected regardless + // of their rcs. This is achieved by using a minrcs value of zero, thus detecting everything. + // key = distance rcs + key = 0.0 0 + key = 5 0 //between 0 and 5 km the min cross section is 0, thus assured detection of everything + key = 10 5 // + key = 20 20 // + key = 30 30 //maxrange of 30km + } + + radarLockTrackCurve + { + // same as detectionCurve, just for locking/tracking purpose + // ATTENTION: DO NOT USE an "assured locking range" here, as this would render lock-breaking + // ECM-jammers & chaff completely ineffective!! + // key = distance rcs + key = 0.0 0 + key = 5 5 // + key = 10 7 // + key = 20 25 // + key = 30 35 //maxrange of 35km + } +} + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1snub.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1snub.mu new file mode 100644 index 000000000..05111e80c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/radome1snub.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/tex_radome125.png b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/tex_radome125.png new file mode 100644 index 000000000..5ca97aad3 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/radome125/tex_radome125.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/model.mu new file mode 100644 index 000000000..1a4f02a7d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/rotaryBombBay.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/rotaryBombBay.cfg new file mode 100644 index 000000000..5d7438ad7 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/rotaryBombBay.cfg @@ -0,0 +1,53 @@ +PART +{ + name = bdRotBombBay + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + node_stack_bottom01 = 0.0, -1.640427, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_move = 0, 0.8677324, 0, 0, 1, 0, 1 + node_attach = 0.0, -1.640427, 0.0, 0.0, -1.0, 0.0, 1 + + TechRequired = precisionEngineering + entryCost = 6200 + cost = 320 + category = none + bdacategory = Missile turrets + subcategory = 0 + bulkheadProfiles = size1 + title = Adjustable Rotary Bomb Rack + manufacturer = Bahamuto Dynamics + description = An adjustable rotary bomb rack. The yellow arrow should be pointing in the direction of weapon release. Missiles or bombs only. One per rail only. + attachRules = 1,1,1,1,0 + mass = 0.375 + dragModelType = default + maximum_drag = 0.1 + minimum_drag = 0.1 + angularDrag = .25 + crashTolerance = 40 + maxTemp = 2000 + fuelCrossFeed = True + thermalMassModifier = 6.0 + emissiveConstant = 0.95 + + MODULE + { + name = BDRotaryRail + + maxLength = 0.94 + maxHeight = 0.22 + + intervals = 6 + + rotationSpeed = 180 + + numberOfRails = 8 + + rotationDelay = 0.08 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/tex_rotBombBay.png b/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/tex_rotBombBay.png new file mode 100644 index 000000000..37dedb3fd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/rotaryBombBay/tex_rotBombBay.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/model.mu new file mode 100644 index 000000000..7806921f8 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/nrm2_NRM.png b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/nrm2_NRM.png new file mode 100644 index 000000000..cdae201e2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/nrm2_NRM.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Launcher.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Launcher.cfg new file mode 100644 index 000000000..e0c0ccdd2 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Launcher.cfg @@ -0,0 +1,70 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaS-8Launcher +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 0.8 + + +// --- node definitions --- +node_attach = 0.0, 0.3988, 0, 0, 1, 0, 0 +node_stack_top = 0.0, 0.3988, 0, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 650 +category = none +bdacategory = Rocket pods +subcategory = 0 +bulkheadProfiles = srf +title = S-8KOM Rocket Pod +manufacturer = Bahamuto Dynamics +description = Holds and fires 23 unguided S-8KOM rockets. It has an aerodynamic nose cone. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.016 +dragModelType = default +maximum_drag = 0.01 +minimum_drag = 0.01 +angularDrag = 2 +crashTolerance = 37 +maxTemp = 3600 + + +MODULE +{ + name = RocketLauncher + shortName = S-8KOM + rocketType = S-8KOMRocket + rocketMass = 0.009 + rocketModelPath = BDArmory/Parts/s-8Launcher/s-8Rocket/model + thrust = 5.49 + thrustTime = 1 + blastRadius = 12 + blastForce = 6 + rippleRPM = 1000 + +} + +RESOURCE +{ + name = S-8KOMRocket + amount = 23 + maxAmount = 23 +} + + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/model.mu new file mode 100644 index 000000000..4e8f29099 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/rocketTexture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/rocketTexture.png new file mode 100644 index 000000000..95ceaa4ad Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/rocketTexture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/srbsmoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/srbsmoke.png new file mode 100644 index 000000000..85af65b2e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/s-8Rocket/srbsmoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/texture.png new file mode 100644 index 000000000..d08a36471 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/s-8Launcher/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/model.mu new file mode 100644 index 000000000..057a68d7e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/sidewinder.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/sidewinder.cfg new file mode 100644 index 000000000..e9b4e5b40 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/sidewinder.cfg @@ -0,0 +1,96 @@ +PART +{ + // Kerbal Space Program - Part Config + + // --- general parameters --- + name = bahaAim9 + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + // --- node definitions --- + node_attach = 0.0, 0.06188124, 0, 0, 1, 0, 0 + node_stack_top = 0.0, 0.06188124, 0, 0, 1, 0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 1200 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = AIM-9 Sidewinder Missile + manufacturer = Bahamuto Dynamics + description = Short range heat seeking missile. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.085 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + shortName = AIM-9 + + thrust = 22 //KN thrust during boost phase + cruiseThrust = 12 //thrust during cruise phase + dropTime = 0.1 //how many seconds after release until engine ignites + boostTime = 3.5 //seconds of boost phase + cruiseTime = 30 //seconds of cruise phase + guidanceActive = true //missile has guidanceActive + maxTurnRateDPS = 45 //degrees per second + decoupleSpeed = 5 + decoupleForward = false + + audioClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostExhaustPrefabPath = BDArmory/Models/exhaust/mediumExhaust + boostExhaustTransformName = boostTransform + boostTransformName = boostTransform + + optimumAirspeed = 894 + + aero = true + liftArea = 0.002 + steerMult = 4 + maxTorque = 35 + maxAoA = 55 + //aeroSteerDamping = 4.5 + torqueRampUp = 50 + + homingType = aam + missileType = missile + targetingType = heat + heatThreshold = 50 + maxOffBoresight = 90 + lockedSensorFOV = 6 + + minStaticLaunchRange = 200 + maxStaticLaunchRange = 15000 + + engageAir = true + engageMissile = false + engageGround = false + engageSLW = false + + } + MODULE + { + name = BDExplosivePart + tntMass = 15 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/texture.png new file mode 100644 index 000000000..cd112fffd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/sidewinder/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/model.mu new file mode 100644 index 000000000..004d01cf5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/part.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/part.cfg new file mode 100644 index 000000000..8ef0ffaed --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/part.cfg @@ -0,0 +1,58 @@ +PART +{ + + +// --- general parameters --- +name = bdWarheadSmall +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + +// --- node definitions --- +// definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z + +node_stack_bottom = 0.0, -0.07750028, 0, 0.0, -1, 0 +node_attach = 0.0, -0.07750028, 0, 0.0, -1, 0 + + + +// --- FX definitions --- + + +// --- editor parameters --- +TechRequired = advAerodynamics +entryCost = 6800 +cost = 180 +category = none +bdacategory = Warheads +subcategory = 0 +bulkheadProfiles = size0 +title = Small High Explosive Warhead +manufacturer = Bahamuto Dynamics +description = A missile nose cone packed with explosives. + +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,1,0,0 +stackSymmetry = 2 + +// --- standard part parameters --- +mass = 0.15 +dragModelType = default +maximum_drag = 0.01 +minimum_drag = 0.01 +angularDrag = .25 +crashTolerance = 30 +maxTemp = 3400 + + + + MODULE + { + name = BDExplosivePart + tntMass = 150 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/texture.png new file mode 100644 index 000000000..b665e3d12 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/smallWarhead/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/model.mu new file mode 100644 index 000000000..8fd188002 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/muzzle.png new file mode 100644 index 000000000..865a9e937 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/part.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/part.cfg new file mode 100644 index 000000000..846737b5a --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/part.cfg @@ -0,0 +1,60 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaSmokeCmPod +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, -0.05, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Countermeasures +subcategory = 0 +bulkheadProfiles = srf +title = Smoke Countermeasure Pod +manufacturer = Bahamuto Dynamics +description = Fires smoke-screen countermeasures for occluding laser points. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.003 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + + +MODULE +{ + name = CMDropper + ejectTransformName = cmTransform + effectsTransformName = effectsTransform + countermeasureType = smoke +} + +RESOURCE +{ + name = CMSmoke + amount = 10 + maxAmount = 10 +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/tex_smokePod.png b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/tex_smokePod.png new file mode 100644 index 000000000..a035eb416 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/smokeCm/tex_smokePod.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/flirBall.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/flirBall.cfg new file mode 100644 index 000000000..3fdc1a091 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/flirBall.cfg @@ -0,0 +1,64 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaFlirBall +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0, -0.07813086, 0, 0, 1, 0 +node_stack_top = 0.0, 0, -0.07813086, 0, 0, -1, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Targeting +subcategory = 0 +bulkheadProfiles = srf +title = FLIR Targeting Ball +manufacturer = Bahamuto Dynamics +description = A ball camera used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.08 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +MODEL +{ + model = BDArmory/Parts/targetingCam/flirBall + texture = texture, BDArmory/Parts/targetingCam/texture +} + + + +MODULE +{ + name = ModuleTargetingCamera + cameraTransformName = camTransform + eyeHolderTransformName = eyeHolderTransform + zoomFOVs = 40,20,4,1.5 + gimbalLimit = 120 + rollCameraModel = false +} + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/flirBall.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/flirBall.mu new file mode 100644 index 000000000..1cdf77aa9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/flirBall.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/model.mu new file mode 100644 index 000000000..0f48a4edb Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/targetingCam.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/targetingCam.cfg new file mode 100644 index 000000000..0a35d0a6f --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/targetingCam.cfg @@ -0,0 +1,61 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = bahaCamPod +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.2792059, -0.1272891, 0, 1, 0, 0 +node_stack_top = 0.0, 0.2792059, -0.1272891, 0, 1, 0, 0 + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Targeting +subcategory = 0 +bulkheadProfiles = srf +title = AN/AAQ-28 Targeting Pod +manufacturer = Bahamuto Dynamics +description = A targeting pod used for targeting and surveillance. Equipped with a high resolution camera with surface and horizon stabilization, and an infrared laser for painting targets, this pod allows you to quickly find and lock grounded targets for missiles. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 1,1,0,0,1 + +// --- standard part parameters --- +mass = 0.2 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 7 +maxTemp = 3600 + +MODEL +{ + model = BDArmory/Parts/targetingCam/model + texture = texture, BDArmory/Parts/targetingCam/texture +} + +MODULE +{ + name = ModuleTargetingCamera + cameraTransformName = camTransform + eyeHolderTransformName = eyeHolderTransform + zoomFOVs = 40,15,3,1 + gimbalLimit = 120 +} + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/texture.png new file mode 100644 index 000000000..91703cb16 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/targetingCam/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/model.mu new file mode 100644 index 000000000..a10cc630e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/tex_towLauncher.png b/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/tex_towLauncher.png new file mode 100644 index 000000000..13ac31aae Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/tex_towLauncher.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/towLauncher.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/towLauncher.cfg new file mode 100644 index 000000000..8c0fb7590 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/towLauncher/towLauncher.cfg @@ -0,0 +1,87 @@ +PART +{ + // Kerbal Space Program - Part Config + + // --- general parameters --- + name = towLauncherTurret + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, -0.3821, -0.2876, 0, -1, 0, 0 + node_stack_missile1 = -0.10422, 0.2239, 0, 0, -1, 0, 0 + node_stack_missile2 = 0.10422, 0.2239, 0, 0, -1, 0, 0 + node_stack_missile3 = -0.10422, -0.0021, 0, 0, -1, 0, 0 + node_stack_missile4 = 0.10422, -0.0021, 0, 0, -1, 0, 0 + + stackSymmetry = 1 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 950 + category = none + bdacategory = Missile turrets + subcategory = 0 + bulkheadProfiles = srf + title = Tow Launcher + manufacturer = Bahamuto Dynamics + description = A turret capable of holding and firing up to 4 TOW missiles. Warranty void if anything except TOW missiles are mounted. To enable the turret, select the mounted missile from the weapon manager. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,1,0,1 + + // --- standard part parameters --- + mass = 0.25 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 60 + maxTemp = 3600 + + + MODULE + { + name = ModuleTurret + + turretID = 0 + + pitchTransformName = pitchTransform + yawTransformName = yawTransform + + pitchSpeedDPS = 75 + yawSpeedDPS = 75 + + maxPitch = 22 + minPitch = -12 + + yawRange = 160 + + smoothRotation = true + smoothMultiplier = 10 + + audioPath = BDArmory/Sounds/hydraulicLoop + maxAudioPitch = 0.65 + minAudioPitch = 0.5 + maxVolume = 0.35 + } + + MODULE + { + name = MissileTurret + + turretID = 0 + + finalTransformName = pitchTransform + + disableRadarYaw = true + } + + + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/model.mu new file mode 100644 index 000000000..8fabac62d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/muzzle.png b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/muzzle.png new file mode 100644 index 000000000..eeaf26119 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/muzzle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/srbsmoke.png b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/srbsmoke.png new file mode 100644 index 000000000..85af65b2e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/srbsmoke.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/tex_towMissile.png b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/tex_towMissile.png new file mode 100644 index 000000000..12828fc31 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/tex_towMissile.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/towMissile.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/towMissile.cfg new file mode 100644 index 000000000..2d715e5a3 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/towMissile/towMissile.cfg @@ -0,0 +1,102 @@ +PART +{ + // Kerbal Space Program - Part Config + // + // + + // --- general parameters --- + name = bahaTowMissile + module = Part + author = BahamutoD + + // --- asset parameters --- + mesh = model.mu + rescaleFactor = 1 + + + // --- node definitions --- + node_attach = 0.0, 0.076, 0, 0, 1, 0, 0 + node_stack_top = 0.0, 0.076, 0, 0, 1, 0, 0 + + // --- editor parameters --- + TechRequired = precisionEngineering + entryCost = 2100 + cost = 120 + category = none + bdacategory = Missiles + subcategory = 0 + bulkheadProfiles = srf + title = BGM-71 Tow Missile + manufacturer = Bahamuto Dynamics + description = Short distance, laser beam-riding, wireless anti-tank missile. + // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision + attachRules = 1,1,0,0,1 + + // --- standard part parameters --- + mass = 0.021 + dragModelType = default + maximum_drag = 0.01 + minimum_drag = 0.01 + angularDrag = 2 + crashTolerance = 5 + maxTemp = 3600 + + + MODULE + { + name = MissileLauncher + + thrust = 24 //KN thrust during boost phase + cruiseThrust = 1.6 //thrust during cruise phase + dropTime = 0 //how many seconds after release until engine ignites + boostTime = .20 //seconds of boost phase + cruiseTime = 7 //seconds of cruise phase + cruiseDelay = 0 //seconds of delay between boost and cruise + guidanceActive = true //missile has guidanceActive + + + deployAnimationName = deployAnimation + deployTime = 0.09 + + decoupleSpeed = 10 + decoupleForward = true + + optimumAirspeed = 320 + + homingType = BeamRiding + targetingType = laser + DetonationDistance = 0 + + beamCorrectionFactor = 4.5 + beamCorrectionDamping = .0075 + + maxAoA = 25 + + aero = true + liftArea = 0.002 + steerMult = .43 + maxTorque = 12 + torqueRampUp = 50000 + aeroSteerDamping = .55 + + minStaticLaunchRange = 650 + maxStaticLaunchRange = 3750 + audioClipPath = BDArmory/Sounds/rocketLoop + boostClipPath = BDArmory/Sounds/rocketLoop + exhaustPrefabPath = BDArmory/Models/exhaust/smallExhaust + boostTransformName = boostTransform + + engageAir = false + engageMissile = false + engageGround = true + engageSLW = false + + } + + MODULE + { + name = BDExplosivePart + tntMass = 10 + } + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/model.mu b/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/model.mu new file mode 100644 index 000000000..9de31da93 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/model.mu differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/texture.png b/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/texture.png new file mode 100644 index 000000000..ce9491254 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/texture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/weaponManager.cfg b/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/weaponManager.cfg new file mode 100644 index 000000000..40684b3da --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Parts/weaponManager/weaponManager.cfg @@ -0,0 +1,62 @@ +PART +{ +// Kerbal Space Program - Part Config +// +// + +// --- general parameters --- +name = missileController +module = Part +author = BahamutoD + +// --- asset parameters --- +mesh = model.mu +rescaleFactor = 1 + + +// --- node definitions --- +node_attach = 0.0, 0.036, 0, 0, -1, 0, 0 + + +// --- editor parameters --- +TechRequired = precisionEngineering +entryCost = 2100 +cost = 600 +category = none +bdacategory = Control +subcategory = 0 +bulkheadProfiles = srf +title = Weapon Manager +manufacturer = Bahamuto Dynamics +description = Cycle through missiles/bombs and fire them with a single button. +// attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision +attachRules = 0,1,0,0,1 + +// --- standard part parameters --- +mass = 0.001 +dragModelType = default +maximum_drag = 0.2 +minimum_drag = 0.2 +angularDrag = 2 +crashTolerance = 25 +maxTemp = 3600 + +PhysicsSignificance = 1 + + +MODULE +{ + name = MissileFire +} + +MODULE +{ + name = RadarWarningReceiver +} + +MODULE +{ + name = ModuleWingCommander +} + +} diff --git a/BDArmory/Distribution/GameData/BDArmory/Resources/Armor.cfg b/BDArmory/Distribution/GameData/BDArmory/Resources/Armor.cfg new file mode 100644 index 000000000..bd0fe71d0 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Resources/Armor.cfg @@ -0,0 +1,11 @@ +// Armor resource for use with armor panels + +RESOURCE_DEFINITION +{ + name = Armor + title = Armor + density = .001 // TODO: find a good density to use so that panels have a reasonable mass at any given armor thickness + flowMode = NO_FLOW + transfer = NONE + isTweakable = true +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Resources/BDAmmo_Universal.cfg b/BDArmory/Distribution/GameData/BDArmory/Resources/BDAmmo_Universal.cfg new file mode 100644 index 000000000..86b065c25 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Resources/BDAmmo_Universal.cfg @@ -0,0 +1,567 @@ +// Warning the values contained within are valid for the current version of BDA (ksp122) do not use these cfgs in earlier versions + +RESOURCE_DEFINITION +{ + name = LaserBolt + title = Laser Plasma + density = .000168 // 1k 268kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 7.62x39Ammo + title = 7.62x39 mm Ammo + density = .000268 // 1k 268kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 7.7x56Ammo + title = 7.7x56 mm Ammo + abbreviation = 7.7/56 + density = .000259 //1k 259kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 7.92x57mmMauser + title = 7.92x57mm Mau Ammo + abbreviation = 7.92Mau + density = .0001 //1k 100kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 9x19mmParaAmmo + title = 9x19 mm Parabellum Ammo + abbreviation = 9x19Para + density = 0.000011838 //1k 188.85g x + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 50CalAmmo + density = .000116942 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +//20x21Ammo +RESOURCE_DEFINITION +{ +name = 20x21Ammo +title 20x21 mm Ammo +abbreviation = 20/21 +density = 0.00011 //1k 110kg +flowMode = ALL_VESSEL +transfer = PUMP +isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 20x102Ammo + density = .000259 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 20x163Ammo + title = 20x163 mm Ammo + abbreviation = 20/163 + density = .0007 //1k 700kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 23x115Ammo + title = 23x115 mm Ammo + abbreviation = 23/115 + density = 0.000498 //1k 498kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 23x152Ammo + title = 23x152 mm Ammo + abbreviation = 23/152 + density = 0.000511 //1k 511kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 25x137Ammo// bradley + title = 25x137 mm Ammo + abbreviation = 25/137 + density = 0.000528 //1k 528kg + + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 30x165Ammo + title = 30x165 mm Ammo + abbreviation = 30long + density = 0.000727 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 30x173Ammo + title = 30x173 mm Ammo + abbreviation = 30AP + density = 0.000741 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 30x173HEAmmo + title = 30x173HE mm Ammo + abbreviation = 30HE + density = 0.000741 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 37mmFlaKAmmo + title = 37 mm FlaK Ammo + abbreviation = 37FlaK + density = 0.0021 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 40x53Ammo + title = 40x53 mm Ammo + abbreviation = 40short + density = 0.001690 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 40x53HeAmmo + title = 40x53 mm HE Ammo + abbreviation = 40HEshort + density = 0.001690 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 40x311Ammo + title = 40x311 mm Ammo + abbreviation = 40/311 + density = 0.00211 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 54cmMortarShells + title = 54 cm Mortar Shell + density = 1 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ +name = 57x438Ammo +title = 57x438 mm Ammo +abbreviation = 57/438 +density = .00151 +flowMode = ALL_VESSEL +transfer = PUMP +isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = TungstenShell + title = Tungsten Shell + abbreviation = Tung + density = .015968 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ +name = 75x714Ammo +title = 75x714 mm Ammo +abbreviation = 75/714 +density = .00151 +flowMode = ALL_VESSEL +transfer = PUMP +isTweakable = true +} + +////76x636Ammo12.5 kg +RESOURCE_DEFINITION +{ +name = 76x636Ammo +title = 76x636mm Ammo +abbreviation = 76/636 +density = 0.0125 +flowMode = ALL_VESSEL +transfer = PUMP +isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 3inchShells + title = 76.2 mm (3") Shell + abbreviation = 3" + density = 0.0056 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 90mmShells + title = 90 mm (3.5") Shell + abbreviation = 90mm + density = 0.0147 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 100mmShells + title = 100 mm (4") Shell + abbreviation = 100mm + density = 0.0187 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = CannonShells + density = 0.0186 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 105mmShells + title = 105mm Shell + abbreviation = 105mm + density = 0.0186 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 105mmHEShells + title = 105mm HE Shell + abbreviation = 105mmHE + density = 0.0186 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 4p5inchQFShells // 114.3d 150 xkm 20 860 + title = 4.5" Quick-Firing Shell + abbreviation = 4.5" + density = 0.02 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 120mmAmmo /// 141 xkm 18.7 860 + title = 120 mm Shell + abbreviation = 120mm + density = 0.0187 //18.7kg + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 122mmQFShells // 162 xkm 25 860 + title = 4.8"122mm Quick-Firing Shell + abbreviation = 4.8"122 + density = 0.02 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 130Shells // 172 xkm 30 860 + title = 130 mm (5.1") Shell + abbreviation = 130mm + density = 0.03 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 5/62Shell // 182 xkm 32.6 860ms + title = 5 inch/62 Shell + abbreviation = 5" //127 + density = .03268 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = QF5-25Shell //133.35c 184 10km 35 860 + title = 5inch1/4 Shell + abbreviation = 5.25" + density = .03568 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 138_140Shells //153 10km 25 860ms + title = 138/140 mm (5.5") Shell + abbreviation = 5.5" + density = 0.025 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 152Shells /// 197 10km 37 960 ms / 177-860ms + title = 152mm (6") Shell + abbreviation = 6" + density = 0.037325 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 155Shells // 216 10km 45 960ms + title = 155mm (6.1") Shell + abbreviation = 6.1-155 + density = 0.04562 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 180Shells //180mm xkm 58kg 960ms + title = 180mm (7.1") Shell + abbreviation = 180mm + density = 0.05 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 203Shells /// 204 xkm 66kg 860ms + title = 203mm (8") Shell + abbreviation = 8" + density = 0.06602 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 12inShells /// 366 xkm 320 960ms + title = 306mm (12") Shell + abbreviation = 12" + density = 0.3208965 //x10 3,2mt + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 356ApAmmo /// 397 xkm 350 960ms + title = 356mmAP (14") Shell + abbreviation = 14"AP + density = 0.35052 + flowMode = NO_FLOW + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 356Shells /// 355 xkm 350 860ms + title = 356mm (14") Shell + abbreviation = 14" + density = 0.35052 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 380Shells ///376 xkm 419 860ms + title = 380/381 mm (15") Shell + abbreviation = 15" + density = 0.4192 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = M65ShellAmmo + title = M65 Shell + density = .8522 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 406mmNuclearShells + title = 406 mm (16") Nuclear Shell + abbreviation = 16"Nuke + density = 0.8864 + flowMode = NO_FLOW + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 16inchShells /// 436 xkm 600 860ms / 486 xkm 600 960ms + title = 406 mm (16") Shell + abbreviation = 16" + density = 0.6 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = 460Shells + title = 460 mm (18.1") Shell + abbreviation = 18" + density = 0.76485 + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = 11inShells /// 283 xkm 250 910ms + title = 283mm (11") Shell + abbreviation = 11" + density = 0.250624 //x10 2,5mt + flowMode = STACK_PRIORITY_SEARCH + transfer = PUMP + isTweakable = true +} + +///////////////////////////////////////// +RESOURCE_DEFINITION +{ + name = Type4Rocket + title = Type 4 AA Rocket + abbreviation = Ty4AAR + density = 0.022 //10 220 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = false +} +RESOURCE_DEFINITION +{ + name = ATRocket + title = Anti-Tank Rocket + abbreviation = ATRa + density = .008212 //10 8.2? + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = Hades122rocket + title = Hades 122mm UG Rocket + abbreviation = Had122 + density = .0322 //10 322 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} +RESOURCE_DEFINITION +{ + name = Hydra70Rocket + title = Hydra-70 rockets + abbreviation = Hyd70 + density = .0122 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = S-8KOMRocket + title = S-8KOM rockets + abbreviation = S8KOM + density = .0036 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Resources/Countermeasures.cfg b/BDArmory/Distribution/GameData/BDArmory/Resources/Countermeasures.cfg new file mode 100644 index 000000000..ee0a31475 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Resources/Countermeasures.cfg @@ -0,0 +1,26 @@ +RESOURCE_DEFINITION +{ + name = CMFlare + density = .0007 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = CMSmoke + density = .0007 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} + +RESOURCE_DEFINITION +{ + name = CMChaff + density = .0007 + flowMode = ALL_VESSEL + transfer = PUMP + isTweakable = true +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Resources/HighExplosive.cfg b/BDArmory/Distribution/GameData/BDArmory/Resources/HighExplosive.cfg new file mode 100644 index 000000000..35a519d43 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/Resources/HighExplosive.cfg @@ -0,0 +1,14 @@ +RESOURCE_DEFINITION +{ + name = HighExplosive + displayName = High Explosive + abbreviation = HE + density = 0.00025 + unitCost = 1.5 + hsp = 920 + isTweakable = true + isVisible = true + flowMode = ALL_VESSEL + transfer = PUMP + volume = 1 +} \ No newline at end of file diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/Artillery_Shot.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/Artillery_Shot.ogg new file mode 100644 index 000000000..555b3caaf Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/Artillery_Shot.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/Jet.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/Jet.ogg new file mode 100644 index 000000000..20946187a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/Jet.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/TorpPropFX.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/TorpPropFX.ogg new file mode 100644 index 000000000..013979046 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/TorpPropFX.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/armOff.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/armOff.ogg new file mode 100644 index 000000000..8b88ee9ee Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/armOff.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/armOn.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/armOn.ogg new file mode 100644 index 000000000..21badfd5a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/armOn.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit1.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit1.ogg new file mode 100644 index 000000000..4b91a6ce6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit1.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit2.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit2.ogg new file mode 100644 index 000000000..c7e39d70d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit2.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit3.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit3.ogg new file mode 100644 index 000000000..eb9780890 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/bulletHit3.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/click.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/click.ogg new file mode 100644 index 000000000..bb653e0a6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/click.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/deployClick.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/deployClick.ogg new file mode 100644 index 000000000..cb00e6433 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/deployClick.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/explode1.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/explode1.ogg new file mode 100644 index 000000000..83fb05b10 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/explode1.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/flareSound.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/flareSound.ogg new file mode 100644 index 000000000..0bfddb70e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/flareSound.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/heatGrowl.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/heatGrowl.ogg new file mode 100644 index 000000000..8c56ecacf Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/heatGrowl.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/hydraulicLoop.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/hydraulicLoop.ogg new file mode 100644 index 000000000..504ae01c0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/hydraulicLoop.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/launch.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/launch.ogg new file mode 100644 index 000000000..b3d3c0899 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/launch.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/mLaunchWarning.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/mLaunchWarning.ogg new file mode 100644 index 000000000..7341bcfc6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/mLaunchWarning.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/missileFlyby.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/missileFlyby.ogg new file mode 100644 index 000000000..8397ffb73 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/missileFlyby.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/popThrust.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/popThrust.ogg new file mode 100644 index 000000000..4f356cb15 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/popThrust.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/reload.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/reload.ogg new file mode 100644 index 000000000..acc0841ba Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/reload.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet1.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet1.ogg new file mode 100644 index 000000000..3fdf4dd6a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet1.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet2.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet2.ogg new file mode 100644 index 000000000..7d2a59473 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet2.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet3.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet3.ogg new file mode 100644 index 000000000..8cba52e4b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/ricochet3.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/rocketLoop.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/rocketLoop.ogg new file mode 100644 index 000000000..2a3ccb7e5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/rocketLoop.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/rwrMissileLock.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwrMissileLock.ogg new file mode 100644 index 000000000..98c474443 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwrMissileLock.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/rwrPing.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwrPing.ogg new file mode 100644 index 000000000..f13172238 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwrPing.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/rwr_sonarping.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwr_sonarping.ogg new file mode 100644 index 000000000..f77afa637 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwr_sonarping.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/rwr_torpedoping.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwr_torpedoping.ogg new file mode 100644 index 000000000..f77afa637 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/rwr_torpedoping.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/shellWhistle.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/shellWhistle.ogg new file mode 100644 index 000000000..fc66c5bf6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/shellWhistle.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/smokeEject.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/smokeEject.ogg new file mode 100644 index 000000000..1ad49f8ce Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/smokeEject.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/smokePoof.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/smokePoof.ogg new file mode 100644 index 000000000..bd39f10bb Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/smokePoof.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/subExplode.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/subExplode.ogg new file mode 100644 index 000000000..c2ab07ddf Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/subExplode.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/warning.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/warning.ogg new file mode 100644 index 000000000..890671c48 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/warning.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Sounds/windloop.ogg b/BDArmory/Distribution/GameData/BDArmory/Sounds/windloop.ogg new file mode 100644 index 000000000..2f71dd93f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Sounds/windloop.ogg differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Ammo.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Ammo.png new file mode 100644 index 000000000..91e70b400 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Ammo.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Bomb.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Bomb.png new file mode 100644 index 000000000..b79ccb5d2 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Bomb.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Control.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Control.png new file mode 100644 index 000000000..273519fbc Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Control.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Countermeasures.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Countermeasures.png new file mode 100644 index 000000000..67a9b2795 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Countermeasures.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Defense.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Defense.png new file mode 100644 index 000000000..8fa2ea07c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Defense.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Gun.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Gun.png new file mode 100644 index 000000000..497336cf7 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Gun.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/GunTurret.png b/BDArmory/Distribution/GameData/BDArmory/Textures/GunTurret.png new file mode 100644 index 000000000..ecf2aff7a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/GunTurret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Infinity.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Infinity.png new file mode 100644 index 000000000..e769e964f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Infinity.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/LaserIcon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/LaserIcon.png new file mode 100644 index 000000000..1a9f0f9a7 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/LaserIcon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/LaserTurret.png b/BDArmory/Distribution/GameData/BDArmory/Textures/LaserTurret.png new file mode 100644 index 000000000..d116c5bf6 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/LaserTurret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Misc.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Misc.png new file mode 100644 index 000000000..e00f5c8c5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Misc.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Missile.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Missile.png new file mode 100644 index 000000000..c51054dcd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Missile.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/MissileTurret.png b/BDArmory/Distribution/GameData/BDArmory/Textures/MissileTurret.png new file mode 100644 index 000000000..54eb70d1a Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/MissileTurret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Radar.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Radar.png new file mode 100644 index 000000000..589a128af Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Radar.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Rocket.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Rocket.png new file mode 100644 index 000000000..0ad929bfb Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Rocket.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/RocketTurret.png b/BDArmory/Distribution/GameData/BDArmory/Textures/RocketTurret.png new file mode 100644 index 000000000..d2c7d1a66 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/RocketTurret.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Targeting.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Targeting.png new file mode 100644 index 000000000..88bfbd43b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Targeting.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/Torpedo.png b/BDArmory/Distribution/GameData/BDArmory/Textures/Torpedo.png new file mode 100644 index 000000000..b2f365f0c Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/Torpedo.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/aimer.png b/BDArmory/Distribution/GameData/BDArmory/Textures/aimer.png new file mode 100644 index 000000000..b7ea4dc4d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/aimer.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/bullet.png b/BDArmory/Distribution/GameData/BDArmory/Textures/bullet.png new file mode 100644 index 000000000..f1f65caef Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/bullet.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/camReticle.png b/BDArmory/Distribution/GameData/BDArmory/Textures/camReticle.png new file mode 100644 index 000000000..f5f8e5df9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/camReticle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/crossedGreenSquare.png b/BDArmory/Distribution/GameData/BDArmory/Textures/crossedGreenSquare.png new file mode 100644 index 000000000..d06ebc8b0 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/crossedGreenSquare.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/directionIcon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/directionIcon.png new file mode 100644 index 000000000..bf5e57874 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/directionIcon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/dottedLargeGreenCircle.png b/BDArmory/Distribution/GameData/BDArmory/Textures/dottedLargeGreenCircle.png new file mode 100644 index 000000000..022f4f7c4 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/dottedLargeGreenCircle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/friendlyContactIcon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/friendlyContactIcon.png new file mode 100644 index 000000000..6a418f15d Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/friendlyContactIcon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/grayscaleRamp.png b/BDArmory/Distribution/GameData/BDArmory/Textures/grayscaleRamp.png new file mode 100644 index 000000000..956d20e4f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/grayscaleRamp.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/greenCircle2.png b/BDArmory/Distribution/GameData/BDArmory/Textures/greenCircle2.png new file mode 100644 index 000000000..813b26393 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/greenCircle2.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/greenCircle3.png b/BDArmory/Distribution/GameData/BDArmory/Textures/greenCircle3.png new file mode 100644 index 000000000..cbcc0dc21 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/greenCircle3.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/greenDiamond.png b/BDArmory/Distribution/GameData/BDArmory/Textures/greenDiamond.png new file mode 100644 index 000000000..86fc23f1f Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/greenDiamond.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/greenDot.png b/BDArmory/Distribution/GameData/BDArmory/Textures/greenDot.png new file mode 100644 index 000000000..40fb24397 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/greenDot.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/greenPointCircle.png b/BDArmory/Distribution/GameData/BDArmory/Textures/greenPointCircle.png new file mode 100644 index 000000000..a7350fd12 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/greenPointCircle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/greenSpikedCircle.png b/BDArmory/Distribution/GameData/BDArmory/Textures/greenSpikedCircle.png new file mode 100644 index 000000000..6c65d5fd7 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/greenSpikedCircle.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/horizonIndicator.png b/BDArmory/Distribution/GameData/BDArmory/Textures/horizonIndicator.png new file mode 100644 index 000000000..9ac0d8abb Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/horizonIndicator.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/icon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/icon.png new file mode 100644 index 000000000..aef73f9cf Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/icon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/icon_rcs.png b/BDArmory/Distribution/GameData/BDArmory/Textures/icon_rcs.png new file mode 100644 index 000000000..c6628a7dd Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/icon_rcs.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/laser.png b/BDArmory/Distribution/GameData/BDArmory/Textures/laser.png new file mode 100644 index 000000000..96a1c23c5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/laser.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/lockedRadarIcon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/lockedRadarIcon.png new file mode 100644 index 000000000..b29965483 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/lockedRadarIcon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/lockedRadarIconActive.png b/BDArmory/Distribution/GameData/BDArmory/Textures/lockedRadarIconActive.png new file mode 100644 index 000000000..c3f41cdff Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/lockedRadarIconActive.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/omniRadarScanTexture.png b/BDArmory/Distribution/GameData/BDArmory/Textures/omniRadarScanTexture.png new file mode 100644 index 000000000..13f63449e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/omniRadarScanTexture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/omniRadarTexture.png b/BDArmory/Distribution/GameData/BDArmory/Textures/omniRadarTexture.png new file mode 100644 index 000000000..01b4dfdc9 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/omniRadarTexture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/openGreenSquare.png b/BDArmory/Distribution/GameData/BDArmory/Textures/openGreenSquare.png new file mode 100644 index 000000000..399c92087 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/openGreenSquare.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/openWhiteSquare.png b/BDArmory/Distribution/GameData/BDArmory/Textures/openWhiteSquare.png new file mode 100644 index 000000000..5c65945c1 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/openWhiteSquare.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/radarContactIcon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/radarContactIcon.png new file mode 100644 index 000000000..97a5b16f8 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/radarContactIcon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/radarRollIndicator.png b/BDArmory/Distribution/GameData/BDArmory/Textures/radarRollIndicator.png new file mode 100644 index 000000000..a8fdc168b Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/radarRollIndicator.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/radialRadarTexture.png b/BDArmory/Distribution/GameData/BDArmory/Textures/radialRadarTexture.png new file mode 100644 index 000000000..f886ff6dc Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/radialRadarTexture.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/resizeSquare.png b/BDArmory/Distribution/GameData/BDArmory/Textures/resizeSquare.png new file mode 100644 index 000000000..d57c9e72e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/resizeSquare.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/rollIndicator.png b/BDArmory/Distribution/GameData/BDArmory/Textures/rollIndicator.png new file mode 100644 index 000000000..1dc800072 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/rollIndicator.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/rollReference.png b/BDArmory/Distribution/GameData/BDArmory/Textures/rollReference.png new file mode 100644 index 000000000..5c35c2c63 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/rollReference.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/rwrDiamond.png b/BDArmory/Distribution/GameData/BDArmory/Textures/rwrDiamond.png new file mode 100644 index 000000000..8a4218bba Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/rwrDiamond.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/rwrMissileIcon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/rwrMissileIcon.png new file mode 100644 index 000000000..781b3c002 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/rwrMissileIcon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/settingsIcon.png b/BDArmory/Distribution/GameData/BDArmory/Textures/settingsIcon.png new file mode 100644 index 000000000..3ed8eb804 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/settingsIcon.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/targetDirectionIndicator.png b/BDArmory/Distribution/GameData/BDArmory/Textures/targetDirectionIndicator.png new file mode 100644 index 000000000..7d6bf0c9e Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/targetDirectionIndicator.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/Textures/whiteSquare.png b/BDArmory/Distribution/GameData/BDArmory/Textures/whiteSquare.png new file mode 100644 index 000000000..44102c1c5 Binary files /dev/null and b/BDArmory/Distribution/GameData/BDArmory/Textures/whiteSquare.png differ diff --git a/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Plane - AA.craft b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Plane - AA.craft new file mode 100644 index 000000000..c383b1aac --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Plane - AA.craft @@ -0,0 +1,10491 @@ +ship = BDA - Test Plane - AA +version = 1.3.1 +description = +type = SPH +size = 13.4111576,4.38962173,12.5597525 +PART +{ + part = probeStackSmall_4291045410 + partName = Part + pos = -1.70568383,11.6839342,5.78061533 + attPos = 0,0,0 + attPos0 = -1.70568383,11.6839342,5.78061533 + rot = 0.707106769,0,0,0.707106769 + attRot = 0,0,0,0.999999881 + attRot0 = 0.707106769,0,0,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bdRadome1_4291057376 + link = advSasModule_4290864070 + attN = bottom,advSasModule_4290864070 + attN = top,bdRadome1_4291057376 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleProbeControlPoint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCommand + isEnabled = True + hibernation = False + hibernateOnWarp = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + MakeReferenceToggle + { + actionGroup = None + } + HibernateToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleReactionWheel + isEnabled = True + actuatorModeCycle = 0 + authorityLimiter = 100 + stateString = Active + stagingEnabled = True + WheelState = Active + EVENTS + { + } + ACTIONS + { + CycleAction + { + actionGroup = None + } + Activate + { + actionGroup = None + } + Deactivate + { + actionGroup = None + } + Toggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSAS + isEnabled = True + standaloneToggle = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleKerbNetAccess + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OpenKerbNetAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleScienceContainer + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + CollectAllAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLogisticsConsumer + isEnabled = True + lastCheck = -1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 2250 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTCA + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + onActionUpdate + { + actionGroup = None + active = False + } + ToggleTCA + { + actionGroup = None + } + } + VSLCONFIG + { + VesselID = 00000000-0000-0000-0000-000000000000 + Name = BDA - Test Plane - AA + Enabled = False + GUIVisible = False + ActiveTab = 0 + ActionGroup = None + WarpToNode = True + AltitudeAboveTerrain = False + DesiredAltitude = 0 + VerticalCutoff = 10 + BlockThrottle = False + ControlSensitivity = 0.00999999978 + ControlTransform = 0 + SteeringGain = 1 + SteeringModifier = 1,1,1 + PitchYawLinked = True + AutoTune = True + SASIsControlled = False + SASWasEnabled = False + MaxNavSpeed = 100 + ShowPath = False + VTOLAssistON = True + AutoGear = True + AutoBrakes = True + StabilizeFlight = True + UseCPS = True + CorrectWithTranslation = True + ShowManualLimits = False + AutoStage = True + AutoParachutes = True + UseSmartEngines = False + Squad = 0 + MacroIsActive = False + EnabledTCAParts + { + } + AT + { + State = None + } + VF + { + State = None + } + CTRL + { + State = None + } + HF + { + State = None + } + BR + { + State = None + } + Nav + { + State = None + } + AP1 + { + State = None + } + AP2 + { + State = None + } + Engines + { + p = 0.400000006 + i = 0.200000003 + } + SmartEngines + { + State = None + } + Path + { + Name = + } + EnginesProfiles + { + ENGINESPROF + { + Name = Default + Active = True + Activated = False + Default = True + NumManual = 0 + OnPlanet = 2 + Stage = -1 + Level = False + SmartEngines = 0 + Groups + { + } + Single + { + 4253169137 + { + Name = J-404 "Panther" Afterburning Turbofan (Dry) + On = False + Limit = 1 + role = MAIN + } + 3040704492 + { + Name = J-404 "Panther" Afterburning Turbofan (Wet) + On = False + Limit = 1 + role = MAIN + } + 2588618808 + { + Name = J-404 "Panther" Afterburning Turbofan (Dry) + On = False + Limit = 1 + role = MAIN + } + 2272412381 + { + Name = J-404 "Panther" Afterburning Turbofan (Wet) + On = False + Limit = 1 + role = MAIN + } + } + } + } + Macros + { + type = ThrottleControlledAvionics.TCAMacroLibrary, ThrottleControlledAvionics + DB + { + } + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MechJebCore + isEnabled = True + running = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnOrbitProgradeAction + { + actionGroup = None + } + OnOrbitRetrogradeAction + { + actionGroup = None + } + OnOrbitNormalAction + { + actionGroup = None + } + OnOrbitAntinormalAction + { + actionGroup = None + } + OnOrbitRadialInAction + { + actionGroup = None + } + OnOrbitRadialOutAction + { + actionGroup = None + } + OnKillRotationAction + { + actionGroup = None + } + OnDeactivateSmartASSAction + { + actionGroup = None + } + OnPanicAction + { + actionGroup = None + } + OnTranslatronOffAction + { + actionGroup = None + } + OnTranslatronKeepVertAction + { + actionGroup = None + } + OnTranslatronZeroSpeedAction + { + actionGroup = None + } + OnTranslatronPlusOneSpeedAction + { + actionGroup = None + } + OnTranslatronMinusOneSpeedAction + { + actionGroup = None + } + OnTranslatronToggleHSAction + { + actionGroup = None + } + OnAscentAPToggleAction + { + actionGroup = None + } + } + MechJebLocalSettings + { + MechJebModuleMenu + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentGuidance + { + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleAscentNavBall + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentPathEditor + { + unlockParts = + unlockTechs = + } + MechJebModuleAttitudeAdjustment + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleCustomWindowEditor + { + unlockParts = + unlockTechs = flightControl + } + MechJebModuleDebugArrows + { + unlockParts = + unlockTechs = + } + MechJebModuleDockingAutopilot + { + forceRol = False + overrideSafeDistance = False + overrideTargetSize = False + unlockParts = + unlockTechs = + rol + { + _val = 0 + _text = 0 + } + } + MechJebModuleDockingGuidance + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleInfoItems + { + unlockParts = + unlockTechs = + } + MechJebModuleLandingAutopilot + { + deployGears = True + deployChutes = True + rcsAdjustment = True + unlockParts = + unlockTechs = + touchdownSpeed + { + _val = 0.5 + _text = 0.5 + } + limitGearsStage + { + val = 0 + _text = 0 + } + limitChutesStage + { + val = 0 + _text = 0 + } + } + MechJebModuleLandingGuidance + { + landingSiteIdx = 0 + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleLandingPredictions + { + unlockParts = + unlockTechs = + } + MechJebModuleManeuverPlanner + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleNodeEditor + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleNodeExecutor + { + unlockParts = + unlockTechs = + } + MechJebModuleRCSBalancerWindow + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleRendezvousAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleRendezvousAutopilotWindow + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleRendezvousGuidance + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleRoverController + { + ControlHeading = False + ControlSpeed = False + BrakeOnEject = False + BrakeOnEnergyDepletion = False + WarpToDaylight = True + StabilityControl = False + LimitAcceleration = False + unlockParts = + unlockTechs = + heading + { + _val = 0 + _text = 0 + } + speed + { + _val = 10 + _text = 10 + } + } + MechJebModuleRoverWindow + { + unlockParts = + unlockTechs = fieldScience + } + MechJebModuleScript + { + minifiedGUI = False + selectedSlot = 0 + activeSavepoint = -1 + unlockParts = + unlockTechs = + } + MechJebModuleSettings + { + unlockParts = + unlockTechs = + } + MechJebModuleSmartASS + { + mode = ORBITAL + target = OFF + advReference = INERTIAL + advDirection = FORWARD + forceRol = False + forcePitch = True + forceYaw = True + unlockParts = + unlockTechs = flightControl + srfHdg + { + _val = 90 + _text = 90 + } + srfPit + { + _val = 90 + _text = 90 + } + srfRol + { + _val = 0 + _text = 0 + } + srfVelYaw + { + _val = 0 + _text = 0 + } + srfVelPit + { + _val = 0 + _text = 0 + } + srfVelRol + { + _val = 0 + _text = 0 + } + rol + { + _val = 0 + _text = 0 + } + } + MechJebModuleSmartRcs + { + unlockParts = + unlockTechs = + } + MechJebModuleSpaceplaneAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleSpaceplaneGuidance + { + runwayIndex = 0 + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleStageStats + { + unlockParts = + unlockTechs = + } + MechJebModuleTargetController + { + unlockParts = + unlockTechs = + } + MechJebModuleThrustWindow + { + autostageSavedState = False + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleTranslatron + { + unlockParts = + unlockTechs = advFlightControl + trans_spd + { + _val = 0 + _text = 0 + } + } + MechJebModuleWarpHelper + { + unlockParts = + unlockTechs = advFlightControl + phaseAngle + { + _val = 0 + _text = 0 + } + } + MechJebModuleWaypointWindow + { + unlockParts = + unlockTechs = + } + MechJebModuleWaypointHelpWindow + { + unlockParts = + unlockTechs = + } + ModExtensionDemo + { + unlockParts = + unlockTechs = + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleWarpController + { + unlockParts = + unlockTechs = + } + MechJebModuleSolarPanelController + { + prev_ShouldOpenSolarPanels = False + unlockParts = + unlockTechs = + } + MechJebModuleThrustController + { + limitThrottle = False + limiterMinThrottle = False + electricThrottle = False + unlockParts = + unlockTechs = + maxThrottle + { + _val = 1 + _text = 100 + } + minThrottle + { + _val = 0.050000000000000003 + _text = 5 + } + electricThrottleLo + { + _val = 0.050000000000000003 + _text = 5 + } + electricThrottleHi + { + _val = 0.14999999999999999 + _text = 15 + } + } + MechJebModuleRCSController + { + unlockParts = + unlockTechs = + Tf + { + _val = 1 + _text = 1 + } + Kp + { + _val = 0.125 + _text = 0.125 + } + Ki + { + _val = 0.070000000000000007 + _text = 0.07 + } + Kd + { + _val = 0.53000000000000003 + _text = 0.53 + } + } + MechJebModuleRCSBalancer + { + unlockParts = + unlockTechs = + } + MechJebModuleAttitudeController + { + unlockParts = + unlockTechs = + } + MechJebModuleStagingController + { + unlockParts = + unlockTechs = + } + MechJebModuleFlightRecorder + { + markUT = 0 + deltaVExpended = 0 + dragLosses = 0 + gravityLosses = 0 + steeringLosses = 0 + markLAN = 0 + markLatitude = 0 + markLongitude = 0 + markAltitude = 0 + markBodyIndex = 1 + maxDragGees = 0 + unlockParts = + unlockTechs = + } + MechJebModuleFlightRecorderGraph + { + unlockParts = + unlockTechs = + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTripLogger + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + Log + { + flight = 0 + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 15 + maxAmount = 15 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bdRadome1_4291057376 + partName = Part + pos = -1.70568383,11.6839342,6.81882095 + attPos = 0,0,0 + attPos0 = 0,1.03819942,-1.19209211E-07 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = bottom01,probeStackSmall_4291045410 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/radome125/tex_radome125 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 320 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = advSasModule_4290864070 + partName = Part + pos = -1.70568383,11.6839342,5.48158884 + attPos = 0,0,0 + attPos0 = 0,-0.299026519,2.98023224E-08 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = mk2SpacePlaneAdapter_4291307528 + link = bahaHiddenVulcan_4291307426 + link = GearSmall_4291307354 + link = bahaCamPod_4291307102 + attN = top,probeStackSmall_4291045410 + attN = bottom,mk2SpacePlaneAdapter_4291307528 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleReactionWheel + isEnabled = True + actuatorModeCycle = 0 + authorityLimiter = 100 + stateString = Active + stagingEnabled = True + WheelState = Active + EVENTS + { + } + ACTIONS + { + CycleAction + { + actionGroup = None + } + Activate + { + actionGroup = None + } + Deactivate + { + actionGroup = None + } + Toggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 1200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = mk2SpacePlaneAdapter_4291307528 + partName = Part + pos = -1.70568383,11.6839342,4.34506035 + attPos = 0,0,0 + attPos0 = 0,-1.13652527,8.94068251E-08 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 320 + modMass = -0.0399999991 + modSize = 0,0,0 + link = MK1IntakeFuselage_4291307486 + link = bahaECMJammer_4291307014 + attN = top,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/FuelTank/mk2Adapters/mk2adapters1m + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 366.399994 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = InterstellarFuelSwitch + isEnabled = True + selectedTankSetup = 2 + configuredAmounts = 400, + configuredFlowStates = True, + selectedTankSetupTxt = LiquidFuel + configLoaded = True + initialTankSetup = LiquidFuel;Oxidizer + storedFactorMultiplier = 1 + storedVolumeMultiplier = 1 + storedMassMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = MK1IntakeFuselage_4291307486 + partName = Part + pos = -1.70568383,11.6839342,4.34506035 + attPos = -0.110681586,0.937499285,-0.991788149 + attPos0 = 0.110681601,-0.937499762,0.991788149 + rot = 0.707106829,0,0,0.707106829 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = 0,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = -0.0450000055 + modSize = 0,0,0 + link = mk2CargoBayL_4291306966 + srfN = srfAttach,mk2SpacePlaneAdapter_4291307528 + attN = bottom,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAnimateHeat + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Structural/mk1Parts/Mk1Structural + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 560 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = InterstellarFuelSwitch + isEnabled = True + selectedTankSetup = 1 + configuredAmounts = 200,2,2, + configuredFlowStates = True,True,True, + selectedTankSetupTxt = LiquidFuel + configLoaded = True + initialTankSetup = IntakeAir;LiquidFuel;IntakeAtm + storedFactorMultiplier = 1 + storedVolumeMultiplier = 1 + storedMassMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 200 + maxAmount = 200 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } + RESOURCE + { + name = IntakeAir + amount = 2 + maxAmount = 2 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 2 + maxAmount = 2 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaHiddenVulcan_4291307426 + partName = Part + pos = -1.70568383,12.3029528,5.37916803 + attPos = 0.00535136461,0,0 + attPos0 = -5.21540642E-08,-0.102420636,-0.619018435 + rot = -6.48255116E-10,1,-1.78813934E-07,1.94289029E-16 + attRot = 0,0,0,1 + attRot0 = 4.58385496E-10,-0.707106709,0.707106948,4.58385219E-10 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = False + defaultDetonationRange = 3500 + useRippleFire = True + engageEnabled = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/hiddenVulcan/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4291307354 + partName = Part + pos = -1.73204029,11.4236469,5.43429327 + attPos = 0,-2.98023224E-08,-0.343781501 + attPos0 = -0.0263563544,-0.0472954996,0.604068756 + rot = -1.78813934E-07,-1.94289029E-16,6.48255116E-10,1 + attRot = 0,0,0,1 + attRot0 = 0.707106948,-4.58385219E-10,-4.58385496E-10,-0.707106709 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = True + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + } + LightOnAction + { + actionGroup = None + } + LightOffAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaCamPod_4291307102 + partName = Part + pos = -2.55462456,11.6839342,4.2815876 + attPos = 0.0343517065,-1.22785342,8.94069458E-08 + attPos0 = -0.883292019,0.0278530046,0 + rot = 0,0,-1,0 + attRot = 8.42937027E-08,0,-0.707106829,0.707106888 + attRot0 = 0,0.707106829,0.707106829,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTargetingCamera + isEnabled = True + cameraEnabled = False + currentFovIndex = 0 + slaveTurrets = False + CoMLock = False + groundStabilized = False + savedLat = 0 + savedLong = 0 + savedAlt = 0 + nvMode = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/targetingCam/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 4000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaECMJammer_4291307014 + partName = Part + pos = -0.905684233,11.6839342,4.1668582 + attPos = -0.442279875,-0.20732379,0 + attPos0 = 1.24227953,0.0291240215,-2.38418437E-07 + rot = 0,0,-0.707106709,0.707106829 + attRot = -7.38817718E-08,0.17364642,-0.984808147,-4.18590787E-07 + attRot0 = 0.50000006,0.49999997,0.49999997,-0.50000006 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2SpacePlaneAdapter_4291307528 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleECMJammer + isEnabled = True + jammerEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + AGDisable + { + actionGroup = None + } + AGToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/ecmJammer/tex_ecmj131 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 6000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = mk2CargoBayL_4291306966 + partName = Part + pos = -1.70568383,11.6839323,1.53255892 + attPos = 0,0,0 + attPos0 = 0,-2.81249809,-5.96046334E-07 + rot = 0,-0.707106829,-0.707106829,0 + attRot = 0,0,0,0.999999881 + attRot0 = 0,-1,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = mk2.1m.Bicoupler_4291306838 + link = sweptWing2_4290972792 + link = sweptWing2_4289761308 + link = BD4x1panelArmor_4291303308 + link = BD4x1panelArmor_4291303162 + link = SurfAntenna_4291302944 + link = bdPilotAI_4291302972 + link = missileController_4291303016 + attN = top,MK1IntakeFuselage_4291307486 + attN = bottom,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCargoBay + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Utility/mk2CargoBay/mk2CargoBay + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = Hangar + isEnabled = True + LaunchWithPunch = False + HangarName = Mk2 Cargo Bay CRG-08 + stagingEnabled = True + hangarState = Inactive + EVENTS + { + } + ACTIONS + { + OpenGatesAction + { + actionGroup = None + } + CloseGatesAction + { + actionGroup = None + } + ToggleGatesAction + { + actionGroup = None + } + ActivateStateAction + { + actionGroup = None + } + DeactivateStateAction + { + actionGroup = None + } + ToggleStateAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = SingleUseHangarStorage + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MultiGeometryAnimator + isEnabled = True + State = Closed + progress = 0 + StopTime = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = mk2.1m.Bicoupler_4291306838 + partName = Part + pos = -1.70568383,11.6839275,-1.27996397 + attPos = 0,0,0 + attPos0 = 0,-2.81250286,-4.76837386E-07 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,-1,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 320 + modMass = -0.0399999991 + modSize = 0,0,0 + link = turboJet_4291306780 + link = turboJet_4291306642 + link = tailfin_4291306504 + link = tailfin_4291306456 + link = delta.small_4291306408 + link = delta.small_4291306330 + link = bahaCmPod_4291306252 + link = bahaCmPod_4291306222 + link = bahaCmPod_4291306192 + link = bahaCmPod_4291306162 + link = bahaChaffPod_4291306132 + link = bahaChaffPod_4291306098 + link = bahaChaffPod_4291306064 + link = bahaChaffPod_4291306030 + attN = top,mk2CargoBayL_4291306966 + attN = bottom01,turboJet_4291306642 + attN = bottom02,turboJet_4291306780 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/FuelTank/mk2Adapters/mk2adapters1m + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 676.400024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = InterstellarFuelSwitch + isEnabled = True + selectedTankSetup = 2 + configuredAmounts = 400, + configuredFlowStates = True, + selectedTankSetupTxt = LiquidFuel + configLoaded = True + initialTankSetup = LiquidFuel;Oxidizer + storedFactorMultiplier = 1 + storedVolumeMultiplier = 1 + storedMassMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = turboJet_4291306780 + partName = Part + pos = -2.33068657,11.6839275,-2.21746874 + attPos = 0,0,0 + attPos0 = -0.625,-0.937502503,0 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = 0 + resPri = 0 + dstg = 0 + sidx = 0 + sqor = 0 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = turboJet_4291306642 + attN = top,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGimbal + isEnabled = True + gimbalLock = False + gimbalLimiter = 100 + currentShowToggles = True + enableYaw = False + enablePitch = True + enableRoll = False + gimbalActive = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + LockAction + { + actionGroup = None + } + FreeAction + { + actionGroup = None + } + TogglePitchAction + { + actionGroup = None + } + ToggleYawAction + { + actionGroup = None + } + ToggleRollAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MultiModeEngine + isEnabled = True + runningPrimary = True + autoSwitch = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ModeAction + { + actionGroup = Custom02 + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + OnAction + { + actionGroup = Custom01 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = True + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = False + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 2000 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/JetEngines + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 2000 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TCAEngineInfo + isEnabled = True + role = 0 + group = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = turboJet_4291306642 + partName = Part + pos = -1.08068156,11.6839275,-2.21746874 + attPos = 0,0,0 + attPos0 = 0.625,-0.937502503,0 + rot = -0.707106829,0,0,-0.707106709 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = 0 + resPri = 0 + dstg = 0 + sidx = 0 + sqor = 0 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = turboJet_4291306780 + attN = top,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGimbal + isEnabled = True + gimbalLock = False + gimbalLimiter = 100 + currentShowToggles = True + enableYaw = False + enablePitch = True + enableRoll = False + gimbalActive = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + LockAction + { + actionGroup = None + } + FreeAction + { + actionGroup = None + } + TogglePitchAction + { + actionGroup = None + } + ToggleYawAction + { + actionGroup = None + } + ToggleRollAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MultiModeEngine + isEnabled = True + runningPrimary = True + autoSwitch = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ModeAction + { + actionGroup = Custom02 + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + OnAction + { + actionGroup = Custom01 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = True + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = False + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 2000 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/JetEngines + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 2000 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TCAEngineInfo + isEnabled = True + role = 0 + group = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = tailfin_4291306504 + partName = Part + pos = -2.90568447,11.6839275,-2.07996798 + attPos = 0.050265789,-0.412341833,-1.13686506E-13 + attPos0 = -1.25026441,-0.387660325,0 + rot = 4.21468478E-08,0.707106709,0.707106829,0 + attRot = 0,0,0,1 + attRot0 = -2.98023224E-08,-1,-5.96046448E-08,-2.98023224E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = tailfin_4291306456 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 750 + Armor = 10 + maxHitPoints = 750 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/airplaneFins/AirplaneFins + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = tailfin_4291306456 + partName = Part + pos = -0.505682945,11.6839275,-2.07997179 + attPos = -0.0502656698,-0.412344694,-1.13686506E-13 + attPos0 = 1.25026441,-0.387660325,0 + rot = 0.707107067,3.0908641E-08,7.30554746E-08,0.70710659 + attRot = 0,0,0,1 + attRot0 = 0,-7.35136965E-08,-2.98023259E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = tailfin_4291306504 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 750 + Armor = 10 + maxHitPoints = 750 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/airplaneFins/AirplaneFins + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4291306408 + partName = Part + pos = -2.3263483,12.1570158,-1.53478956 + attPos = 0.24300468,0.244145393,0.0255527496 + attPos0 = -0.863668978,-0.498970509,-0.498639941 + rot = 0.500000298,-0.499999851,-0.499999851,0.50000006 + attRot = -0.0206821579,0.499572128,0.035822738,0.865284204 + attRot0 = -0.0107059469,0.258597523,0.0399549939,-0.965099096 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon2_4291306368 + sym = delta.small_4291306330 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4291306368 + partName = Part + pos = -2.3263483,13.1117964,-2.15979481 + attPos = 0,0,0 + attPos0 = -0.954778433,-0.625002265,5.96046448E-08 + rot = 0.49999997,-0.50000006,-0.50000006,0.49999997 + attRot = 0.707106709,0.707106709,0,0 + attRot0 = -1.05367128E-07,-5.96046448E-08,1.05367128E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4291306290 + srfN = srfAttach,delta.small_4291306408 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = False + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4291306330 + partName = Part + pos = -1.08501935,12.1570158,-1.53479147 + attPos = -0.243004799,0.244143486,0.0255527496 + attPos0 = 0.863669038,-0.498970509,-0.498639941 + rot = 0.50000006,-0.499999821,-0.500000179,0.49999997 + attRot = -0.0206821579,0.499572128,0.035822738,0.865284204 + attRot0 = 0,0.707106829,0,-0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon2_4291306290 + sym = delta.small_4291306408 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4291306290 + partName = Part + pos = -1.08501911,13.1117983,-2.15979719 + attPos = 0,0,0 + attPos0 = -0.95477879,-0.625003994,1.19209318E-07 + rot = 0.50000006,-0.49999997,-0.49999997,0.50000006 + attRot = 0.707106709,0.707106709,0,0 + attRot0 = 0,5.96046306E-08,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4291306368 + srfN = srfAttach,delta.small_4291306330 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = False + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaCmPod_4291306252 + partName = Part + pos = -0.579705477,11.224947,-1.36127424 + attPos = 0,0,0 + attPos0 = 1.11864269,-0.0813107491,0.464496017 + rot = 0.656742096,0.262087405,0.674054205,-0.213660866 + attRot = 0.0294955131,0.708637536,-0.0294955727,0.70433861 + attRot0 = -0.615467966,-0.661952078,-0.291304439,-0.313305706 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306222 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4291306222 + partName = Part + pos = -2.83166218,11.224947,-1.36127234 + attPos = 0,0,0 + attPos0 = -1.11864269,-0.0813107491,0.464496017 + rot = -0.656742096,0.262087405,0.674054205,0.213660866 + attRot = 0.0294955131,0.708637536,-0.0294955727,0.70433861 + attRot0 = 0.602746069,-0.648269236,-0.31679064,0.340716779 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306252 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4291306192 + partName = Part + pos = -0.590071559,11.2386112,-1.12328148 + attPos = 0,0,0 + attPos0 = 1.11062706,0.15667963,0.448957801 + rot = 0.660269976,0.253068328,0.676917136,-0.20440942 + attRot = 0.0198426098,0.708272815,-0.0198425669,0.705380797 + attRot0 = -0.611420691,-0.657599032,-0.29970634,-0.322342128 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306162 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4291306162 + partName = Part + pos = -2.82129669,11.2386112,-1.12328053 + attPos = 0,0,0 + attPos0 = -1.11062706,0.15667963,0.448957801 + rot = -0.660270095,0.253068238,0.676917136,0.204409376 + attRot = 0.0198426098,0.708272815,-0.0198425669,0.705380797 + attRot0 = 0.602746069,-0.648269236,-0.31679064,0.340716779 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306192 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306132 + partName = Part + pos = -0.620878935,11.2725124,-0.646722317 + attPos = 0.00667023659,1.90734863E-06,-0.00398445129 + attPos0 = 1.07813334,0.633237362,0.415398985 + rot = 0.65625453,0.263305932,0.680280209,-0.192921668 + attRot = 0.04573825,0.710440099,-0.0457382686,0.700778663 + attRot0 = -0.600458264,-0.667216182,-0.294845432,-0.327625871 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306098 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306098 + partName = Part + pos = -2.79048872,11.2725124,-0.646720409 + attPos = -0.0066703558,2.86102295E-06,-0.00398445129 + attPos0 = -1.07813334,0.633237362,0.415398985 + rot = -0.656254649,0.263305873,0.680280209,0.192921579 + attRot = 0.04573825,0.710440099,-0.0457382686,0.700778663 + attRot0 = 0.580008984,-0.644493341,-0.333276927,0.370330185 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306132 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306064 + partName = Part + pos = -0.603674173,11.2518826,-0.883910179 + attPos = 0.00233459473,3.81469727E-06,0.000204086304 + attPos0 = 1.09967422,0.396049023,0.431839377 + rot = 0.657037377,0.261346132,0.680853069,-0.190890476 + attRot = 0.043643862,0.710353017,-0.0436438099,0.701133966 + attRot0 = -0.599575639,-0.666235387,-0.296636194,-0.329615653 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306030 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306030 + partName = Part + pos = -2.80769396,11.2518826,-0.883909225 + attPos = -0.00233471394,4.76837158E-06,0.000204086304 + attPos0 = -1.09967422,0.396049023,0.431839377 + rot = -0.657037556,0.261346072,0.680853009,0.190890491 + attRot = 0.043643862,0.710353017,-0.0436438099,0.701133966 + attRot0 = 0.580008984,-0.644493341,-0.333276927,0.370330185 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306064 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = sweptWing2_4290972792 + partName = Part + pos = -2.78617907,11.6839323,1.93255687 + attPos = -0.172393918,0.308313549,-2.38418721E-07 + attPos0 = 1.25288868,0.0916850492,0 + rot = 0.707106829,0,4.21468478E-08,0.707106709 + attRot = 0,0,0,1 + attRot0 = 2.98023224E-08,1,-5.96046448E-08,-2.98023224E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = delta.small_4290963530 + link = GearSmall_4290886262 + link = structuralWing2_4290941810 + link = bahaAdjustableRail_4289561748 + link = bahaAdjustableRail_4290666516 + link = bahaAdjustableRail_4291290842 + sym = sweptWing2_4289761308 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4290963530 + partName = Part + pos = -6.53625774,11.6839314,0.688214779 + attPos = 0,0,0 + attPos0 = -3.75007486,-1.24433625,7.26427004E-07 + rot = 0.707106948,-1.89660909E-07,-1.26440398E-07,0.70710659 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,-2.53319683E-07,1.49012802E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = StandardCtrlSrf_4290871432 + sym = delta.small_4289760992 + srfN = srfAttach,sweptWing2_4290972792 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = StandardCtrlSrf_4290871432 + partName = Part + pos = -7.46995831,11.6839333,0.06320858 + attPos = 0,0,0 + attPos0 = -0.933689117,-0.625001431,-4.07147205E-08 + rot = 0.707106709,1.12381446E-08,-3.09086658E-08,0.707106829 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = -4.17232513E-07,2.0960826E-07,-7.45058202E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = StandardCtrlSrf_4289760942 + srfN = srfAttach,delta.small_4290963530 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = False + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 400 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4290886262 + partName = Part + pos = -3.78150034,11.6839352,0.914793491 + attPos = -0.198512137,-0.647987127,-2.8504794E-06 + attPos0 = -0.7968086,-0.369776458,1.72785121E-07 + rot = 8.94069672E-08,1.04308128E-07,1.12531438E-07,1 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = -0.707106829,1.53328713E-07,-3.6332132E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = GearSmall_4289761258 + srfN = srfAttach,sweptWing2_4290972792 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = True + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + } + LightOnAction + { + actionGroup = None + } + LightOffAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralWing2_4290941810 + partName = Part + pos = -2.78617907,11.6839314,0.677497387 + attPos = 2.38166881,-0.421416581,1.92194932E-07 + attPos0 = -2.38166881,-0.83363992,-4.25805347E-08 + rot = -0.707107067,1.89660824E-07,-2.31807604E-07,-0.70710659 + attRot = 0,0,0,1 + attRot0 = -1.78813906E-07,-7.10542651E-15,-2.68220873E-07,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon3_4290934650 + link = elevon2_4290937476 + link = bahaAdjustableRail_4291497768 + sym = structuralWing2_4289760306 + srfN = srfAttach,sweptWing2_4290972792 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon3_4290934650 + partName = Part + pos = -3.78717566,11.6839323,0.0524892807 + attPos = 0,0,0 + attPos0 = -1.00099444,-0.62500149,8.9348049E-08 + rot = 0.707106829,-2.31807775E-07,2.31807633E-07,0.707106709 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon3_4289760214 + srfN = srfAttach,structuralWing2_4290941810 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 650 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4290937476 + partName = Part + pos = -5.63693953,11.6839314,0.0524892807 + attPos = 0,0,0 + attPos0 = -2.85075283,-0.625001609,-2.09060911E-08 + rot = 0.707106829,-2.31807775E-07,2.31807633E-07,0.707106709 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4289760256 + srfN = srfAttach,structuralWing2_4290941810 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291497768 + partName = Part + pos = -3.20494032,11.5481815,1.55697489 + attPos = 6.85453415E-07,0.563208461,-2.23517418E-06 + attPos0 = -0.418760389,0.31626749,0.135751575 + rot = 3.27825546E-07,-2.9802311E-07,-1.64771549E-07,1 + attRot = 0,0,0,1 + attRot0 = 0.707106829,1.3758455E-07,1.37584607E-07,-0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaHarm_4290714558 + sym = bahaAdjustableRail_4291499546 + srfN = srfAttach,structuralWing2_4290941810 + attN = bottom,bahaHarm_4290714558 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.159999996 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4289561748 + partName = Part + pos = -6.76383305,11.5481892,0.969477177 + attPos = -0.233245134,-3.51667404E-06,8.94069672E-08 + attPos0 = -3.74440455,-0.963077247,0.135743037 + rot = 3.27825546E-07,-2.98023508E-08,2.5949231E-07,1 + attRot = 0,0,0,1 + attRot0 = 0.70710665,-1.62415361E-07,-1.62415319E-07,-0.707106888 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAdjustableRail_4291520440 + link = bahaAdjustableRail_4291519632 + sym = bahaAdjustableRail_4292092974 + srfN = srfAttach,sweptWing2_4290972792 + attN = left,bahaAdjustableRail_4291520440 + attN = right,bahaAdjustableRail_4291519632 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0799999982 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291520440 + partName = Part + pos = -6.67751646,11.4446774,1.00307322 + attPos = 0,0,0 + attPos0 = 0.0862912312,-0.183523223,0.0335990377 + rot = 0.707107008,-0.70710665,-1.1920929E-07,0 + attRot = -0.49999994,-0.49999994,0.49999994,-0.49999994 + attRot0 = 0.707106531,-0.707107067,1.7881392E-07,2.08616228E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim9_4290651952 + sym = bahaAdjustableRail_4291524646 + attN = top,bahaAdjustableRail_4289561748 + attN = left,bahaAim9_4290651952 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0799999982 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4290651952 + partName = Part + pos = -6.57399178,11.3385067,0.986273289 + attPos = 0,0,0 + attPos0 = 0.106171727,-0.103524916,0.016799489 + rot = 0,2.35367281E-14,8.72860184E-09,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0.707106948,-0.70710665,-2.11795559E-09,-1.53397224E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4291520440 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-9 + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 9.12498474 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 200 + engageRangeMax = 8000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 15 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291519632 + partName = Part + pos = -6.85011053,11.4446774,0.969473362 + attPos = 0,0,0 + attPos0 = -0.0862913951,-0.183523118,-8.64267065E-07 + rot = 5.96046377E-08,1.7881392E-07,-0.707106888,0.707106709 + attRot = -0.49999994,0.49999994,0.49999994,0.49999994 + attRot0 = 2.38418551E-07,2.00416935E-07,0.707107008,-0.707106709 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim9_4290650954 + sym = bahaAdjustableRail_4291525380 + attN = top,bahaAdjustableRail_4289561748 + attN = left,bahaAim9_4290650954 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0799999982 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4290650954 + partName = Part + pos = -6.95363235,11.3385067,0.986273289 + attPos = 0,0,0 + attPos0 = 0.10617172,-0.103521794,0.0168003775 + rot = 0,-3.90798471E-14,-2.1073765E-08,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 1.4462529E-08,4.01196871E-08,-0.707106948,-0.707106709 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4291519632 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-9 + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 9.12498474 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 200 + engageRangeMax = 8000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 15 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = sweptWing2_4289761308 + partName = Part + pos = -0.62518847,11.6839323,1.93255782 + attPos = 0.172393918,0.308314025,-2.38418721E-07 + attPos0 = -1.25288868,0.0916850492,0 + rot = 1.12382352E-08,0.707106829,0.707106829,-3.09086197E-08 + attRot = 0,0,0,1 + attRot0 = 0,1.39090748E-08,2.98023117E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = delta.small_4289760992 + link = GearSmall_4289761258 + link = structuralWing2_4289760306 + link = bahaAdjustableRail_4292092974 + link = bahaAdjustableRail_4291288994 + link = bahaAdjustableRail_4291288850 + sym = sweptWing2_4290972792 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4289760992 + partName = Part + pos = 3.12489462,11.6839314,0.688214779 + attPos = 0,0,0 + attPos0 = -3.75007486,-1.24433625,7.26427004E-07 + rot = -1.57349035E-07,0.70710665,0.707106888,-2.20569575E-07 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,-2.53319683E-07,1.49012802E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = StandardCtrlSrf_4289760942 + sym = delta.small_4290963530 + srfN = srfAttach,sweptWing2_4289761308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = StandardCtrlSrf_4289760942 + partName = Part + pos = 4.05859423,11.6839333,0.06320858 + attPos = 0,0,0 + attPos0 = -0.933689117,-0.625001431,-4.07147205E-08 + rot = -6.18173317E-08,0.707106829,0.707106709,-1.96704679E-08 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = -4.17232513E-07,2.0960826E-07,-7.45058202E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = StandardCtrlSrf_4290871432 + srfN = srfAttach,delta.small_4289760992 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = False + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 400 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4289761258 + partName = Part + pos = 0.370133758,11.6839352,0.914793491 + attPos = -0.19851166,-0.647989035,2.66054917E-06 + attPos0 = -0.7968086,-0.369776458,1.72785121E-07 + rot = -8.94069672E-08,1.04308135E-07,1.12531431E-07,-1 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = -0.707106829,1.53328713E-07,-3.6332132E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = GearSmall_4290886262 + srfN = srfAttach,sweptWing2_4289761308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = True + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + } + LightOnAction + { + actionGroup = None + } + LightOffAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralWing2_4289760306 + partName = Part + pos = -0.62518847,11.6839323,0.677497387 + attPos = 2.38166714,-0.421417356,6.62534347E-08 + attPos0 = -2.38166714,-0.833640575,-6.62534347E-08 + rot = 2.00899024E-07,0.70710659,0.707106948,-2.20569376E-07 + attRot = 0,0,0,1 + attRot0 = -2.68220873E-07,4.44089167E-15,2.68220788E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon3_4289760214 + link = elevon2_4289760256 + link = bahaAdjustableRail_4291499546 + sym = structuralWing2_4290941810 + srfN = srfAttach,sweptWing2_4289761308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon3_4289760214 + partName = Part + pos = 0.375809312,11.6839323,0.0524892807 + attPos = 0,0,0 + attPos0 = -1.00099444,-0.62500149,8.9348049E-08 + rot = 2.00899152E-07,0.707106829,0.707106829,-2.62716526E-07 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon3_4290934650 + srfN = srfAttach,structuralWing2_4289760306 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 650 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4289760256 + partName = Part + pos = 2.22557592,11.6839323,0.0524892807 + attPos = 0,0,0 + attPos0 = -2.85075283,-0.625001609,-2.09060911E-08 + rot = 2.00899152E-07,0.707106829,0.707106829,-2.62716526E-07 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4290937476 + srfN = srfAttach,structuralWing2_4289760306 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291499546 + partName = Part + pos = -0.206426978,11.5481806,1.55697298 + attPos = 6.85453415E-07,0.563207507,1.2665987E-06 + attPos0 = -0.418760389,0.31626749,-0.135752574 + rot = 2.68220873E-07,2.98022911E-07,1.6477162E-07,1 + attRot = 0,0,0,1 + attRot0 = -1.06676012E-07,-0.707106829,-0.707106829,1.06676097E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaHarm_4290716828 + sym = bahaAdjustableRail_4291497768 + srfN = srfAttach,structuralWing2_4289760306 + attN = bottom,bahaHarm_4290716828 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.159999996 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4292092974 + partName = Part + pos = 3.35246706,11.5481892,0.969479084 + attPos = -0.233244419,-1.90734863E-06,-8.94069672E-08 + attPos0 = -3.74440193,-0.96307826,-0.135743126 + rot = -3.27825546E-07,-2.98023153E-08,2.5949231E-07,-1 + attRot = 0,0,0,1 + attRot0 = -1.93323928E-07,0.707107067,0.70710659,1.93323913E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAdjustableRail_4291524646 + link = bahaAdjustableRail_4291525380 + sym = bahaAdjustableRail_4289561748 + srfN = srfAttach,sweptWing2_4289761308 + attN = left,bahaAdjustableRail_4291525380 + attN = right,bahaAdjustableRail_4291524646 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0799999982 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291524646 + partName = Part + pos = 3.26615334,11.4446783,1.00307322 + attPos = 0,0,0 + attPos0 = -0.0862912759,-0.183523193,0.0335990563 + rot = -0.707106888,-0.707106709,2.98023224E-08,-5.96046448E-08 + attRot = -0.49999994,-0.49999994,0.49999994,-0.49999994 + attRot0 = 0.70710659,0.707106948,-2.01361246E-07,2.68220901E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim9_4291528600 + sym = bahaAdjustableRail_4291520440 + attN = top,bahaAdjustableRail_4292092974 + attN = right,bahaAim9_4291528600 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0799999982 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4291528600 + partName = Part + pos = 3.16262865,11.3385067,0.986273289 + attPos = 0,0,0 + attPos0 = -0.106171653,-0.103524812,0.0167994294 + rot = 0,2.34923192E-13,-8.72860539E-09,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = -0.707106829,-0.707106769,-9.3729966E-09,-1.44625334E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4291524646 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-9 + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 9.12498474 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 200 + engageRangeMax = 8000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 15 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291525380 + partName = Part + pos = 3.43874264,11.4446783,0.969473362 + attPos = 0,0,0 + attPos0 = 0.0862914696,-0.183523148,-8.04662875E-07 + rot = 0,-2.08616257E-07,0.707106948,0.707106709 + attRot = -0.49999994,0.49999994,0.49999994,0.49999994 + attRot0 = 2.68220901E-07,-2.08616257E-07,-0.707107008,-0.70710659 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim9_4291529322 + sym = bahaAdjustableRail_4291519632 + attN = top,bahaAdjustableRail_4292092974 + attN = right,bahaAim9_4291529322 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0799999982 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4291529322 + partName = Part + pos = 3.54226446,11.3385067,0.986273289 + attPos = 0,0,0 + attPos0 = -0.106171705,-0.103521496,0.0168004297 + rot = 0,2.58904009E-13,-8.72854145E-09,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 1.4462529E-08,-1.51129626E-07,0.707106888,-0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4291525380 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-9 + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 9.12498474 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 200 + engageRangeMax = 8000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 15 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = BD4x1panelArmor_4291303308 + partName = Part + pos = -2.30322695,11.8662891,1.57295465 + attPos = -0.152653575,-0.899919868,0.221671417 + attPos0 = 0.750196397,0.940315127,-0.0393154733 + rot = 0.512917221,-0.486739904,-0.486740321,0.512917221 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,-0.725374341,-5.96046448E-08,-0.688354611 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = UniversalAmmoBoxBDA_4291303198 + sym = BD4x1panelArmor_4291303162 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 13000 + Armor = 150 + maxHitPoints = 0 + ArmorThickness = 150 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/ArmorPlate/armorpanelNRM + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleHullBreach + isEnabled = True + hydroExplosive = False + hull = False + crushDepth = 200 + DepthCharge = False + partDebug = True + flowMultiplier = 1 + crushable = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = UniversalAmmoBoxBDA_4291303198 + partName = Part + pos = -2.05094028,12.0210218,2.42331147 + attPos = 0,0,0 + attPos0 = -0.141316891,0.850357771,-0.260038227 + rot = -0.0261769444,0.999657393,2.98023224E-08,-3.37138772E-07 + attRot = 0,0,0,1 + attRot0 = -0.49999994,0.5,-0.50000006,-0.49999994 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = UniversalAmmoBoxBDA_4291303052 + srfN = srfAttach,BD4x1panelArmor_4291303308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FSfuelSwitch + isEnabled = True + selectedTankSetup = 7 + hasLaunched = False + configLoaded = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1 + defaultScale = 1 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = BD4x1panelArmor_4291303162 + partName = Part + pos = -1.10814035,11.8662872,1.57295465 + attPos = 0.152653337,-0.899919868,0.221670464 + attPos0 = -0.750196397,0.940315127,-0.0393154733 + rot = -0.512917221,-0.486739874,-0.486740172,-0.51291734 + attRot = 0,0,0,1 + attRot0 = -1.1920929E-07,-0.72537446,-2.98023224E-08,0.688354552 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = UniversalAmmoBoxBDA_4291303052 + sym = BD4x1panelArmor_4291303308 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 13000 + Armor = 150 + maxHitPoints = 0 + ArmorThickness = 150 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/ArmorPlate/armorpanelNRM + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleHullBreach + isEnabled = True + hydroExplosive = False + hull = False + crushDepth = 200 + DepthCharge = False + partDebug = True + flowMultiplier = 1 + crushable = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = UniversalAmmoBoxBDA_4291303052 + partName = Part + pos = -1.36042702,12.0210218,2.42331147 + attPos = 0,0,0 + attPos0 = 0.14131777,0.850357831,-0.260038644 + rot = 0.0261770487,0.999657393,0,1.05239451E-07 + attRot = 0,0,0,1 + attRot0 = -0.49999994,-0.50000006,0.50000006,-0.50000006 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = UniversalAmmoBoxBDA_4291303198 + srfN = srfAttach,BD4x1panelArmor_4291303162 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FSfuelSwitch + isEnabled = True + selectedTankSetup = 7 + hasLaunched = False + configLoaded = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1 + defaultScale = 1 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = SurfAntenna_4291302944 + partName = Part + pos = -1.63763762,12.4617033,0.851433277 + attPos = 0,0,0 + attPos0 = -0.0680461228,-0.681126595,0.777770758 + rot = 0.0308435559,0.706433773,0.0308435559,-0.706433773 + attRot = 0,0.707106709,0,0.707106709 + attRot0 = -0.477714419,-0.477714419,-0.521333814,-0.521333814 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4290666516 + partName = Part + pos = -5.53100014,11.6419315,1.6983757 + attPos = -0.144100428,0.0783252418,-3.85940075E-06 + attPos0 = -2.74482059,-0.234181359,0.0420006663 + rot = 3.27825546E-07,3.87430276E-07,-2.52880994E-07,-1 + attRot = 2.17345132E-07,2.59491998E-07,-0.707106948,-0.70710659 + attRot0 = 0.707107127,9.51406207E-08,-4.10621595E-07,-0.707106531 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4290655752 + sym = bahaAdjustableRail_4291288994 + srfN = srfAttach,sweptWing2_4290972792 + attN = bottom,bahaAim120_4290655752 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4290655752 + partName = Part + pos = -5.53096628,11.3620739,1.89019299 + attPos = 0,0,0 + attPos0 = 1.73582862E-06,-0.319874257,0.19180043 + rot = -6.55651093E-07,3.8742985E-07,-7.18194656E-07,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 1.10268604E-06,-7.10542804E-14,4.65313349E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAim120_4291288930 + attN = top,bahaAdjustableRail_4290666516 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291288994 + partName = Part + pos = 2.11963558,11.6419315,1.6983757 + attPos = -0.144100428,0.0783252418,-3.85940075E-06 + attPos0 = -2.74482059,-0.234182194,-0.0420008339 + rot = -5.36441803E-07,3.8743039E-07,-2.52880938E-07,1 + attRot = 2.17345132E-07,2.59491998E-07,-0.707106948,-0.70710659 + attRot0 = 4.41530233E-07,-0.707106471,-0.707107186,6.42321893E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4291288930 + sym = bahaAdjustableRail_4290666516 + srfN = srfAttach,sweptWing2_4289761308 + attN = bottom,bahaAim120_4291288930 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4291288930 + partName = Part + pos = 2.11960125,11.3620739,1.89019394 + attPos = 0,0,0 + attPos0 = 1.73582862E-06,-0.319874257,0.19180043 + rot = 5.66244125E-07,3.87429907E-07,-7.1819494E-07,1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 1.10268604E-06,-7.10542804E-14,4.65313349E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAim120_4290655752 + attN = top,bahaAdjustableRail_4291288994 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291290842 + partName = Part + pos = -4.53595495,11.6419315,2.31991816 + attPos = -0.144100428,0.0783252418,-3.85940075E-06 + attPos0 = -1.74977505,0.387361377,0.0420006141 + rot = 3.27825546E-07,3.87430276E-07,-2.52880994E-07,-1 + attRot = 2.17345132E-07,2.59491998E-07,-0.707106948,-0.70710659 + attRot0 = 0.707107127,9.51406207E-08,-4.10621595E-07,-0.707106531 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4291290778 + sym = bahaAdjustableRail_4291288850 + srfN = srfAttach,sweptWing2_4290972792 + attN = bottom,bahaAim120_4291290778 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4291290778 + partName = Part + pos = -4.53592062,11.3620749,2.51173663 + attPos = 0,0,0 + attPos0 = 1.73582862E-06,-0.319874257,0.19180043 + rot = -6.55651093E-07,3.8742985E-07,-7.18194656E-07,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 1.10268604E-06,-7.10542804E-14,4.65313349E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAim120_4291288780 + attN = top,bahaAdjustableRail_4291290842 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291288850 + partName = Part + pos = 1.12458909,11.6419315,2.31991816 + attPos = -0.144100428,0.0783252418,-3.85940075E-06 + attPos0 = -1.74977505,0.387360185,-0.0420008078 + rot = -5.36441803E-07,3.8743039E-07,-2.52880938E-07,1 + attRot = 2.17345132E-07,2.59491998E-07,-0.707106948,-0.70710659 + attRot0 = 4.41530233E-07,-0.707106471,-0.707107186,6.42321893E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4291288780 + sym = bahaAdjustableRail_4291290842 + srfN = srfAttach,sweptWing2_4289761308 + attN = bottom,bahaAim120_4291288780 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 0.600000024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4291288780 + partName = Part + pos = 1.12455499,11.3620739,2.51173592 + attPos = 0,0,0 + attPos0 = 1.73582862E-06,-0.319874257,0.19180043 + rot = 5.66244125E-07,3.87429907E-07,-7.1819494E-07,1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 1.10268604E-06,-7.10542804E-14,4.65313349E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAim120_4291290778 + attN = top,bahaAdjustableRail_4291288850 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaHarm_4290716828 + partName = Part + pos = -0.206431627,11.1920929,1.9737854 + attPos = 0,0,0 + attPos0 = -6.5520976E-07,-0.196083888,0.416801155 + rot = 0,-9.23214345E-14,-2.82616609E-14,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 2.6822093E-07,2.98022911E-07,1.64771635E-07,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaHarm_4290714558 + attN = top,bahaAdjustableRail_4291499546 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = HARM + maxStaticLaunchRange = 30000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 0 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 30000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 70 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaHarm_4290714558 + partName = Part + pos = -3.20493793,11.1920929,1.97378063 + attPos = 0,0,0 + attPos0 = 5.23340418E-07,-0.196083769,0.416801244 + rot = -1.78813934E-07,-1.32103286E-13,-4.66902518E-14,-1 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 2.68220901E-07,-2.98023139E-07,-1.64771492E-07,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaHarm_4290716828 + attN = top,bahaAdjustableRail_4291497768 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = HARM + maxStaticLaunchRange = 30000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 0 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 30000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 70 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bdPilotAI_4291302972 + partName = Part + pos = -1.70568383,12.4387293,1.89704823 + attPos = 0,0,0 + attPos0 = 0,0.364489079,0.754794598 + rot = 9.87817117E-09,-1,1.78813934E-07,-4.4408921E-16 + attRot = 0,0,0,1 + attRot0 = 0.707106888,6.98491975E-09,-6.98492153E-09,0.70710665 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDModulePilotAI + isEnabled = True + pilotEnabled = False + defaultAltitude = 2000 + minAltitude = 500 + steerMult = 8 + pitchKiAdjust = 0 + maxSteer = 1 + steerDamping = 3 + maxSpeed = 800 + takeOffSpeed = 90 + minSpeed = 80 + idleSpeed = 120 + maxAllowedGForce = 18 + maxAllowedAoA = 45 + standbyMode = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGActivatePilot + { + actionGroup = None + } + AGDeactivatePilot + { + actionGroup = None + } + AGTogglePilot + { + actionGroup = Custom10 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileController_4291303016 + partName = Part + pos = -1.70568383,12.3784914,3.07297325 + attPos = 0,0,0 + attPos0 = 0,1.54041207,0.694557667 + rot = 9.87817117E-09,-1,1.78813934E-07,-4.4408921E-16 + attRot = 0,0,0,1 + attRot0 = 0.707106888,6.98491975E-09,-6.98492153E-09,0.70710665 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileFire + isEnabled = True + weaponIndex = 0 + targetScanInterval = 3 + fireBurstLength = 0 + guardAngle = 360 + guardRange = 10000 + gunRange = 2500 + maxMissilesOnTarget = 1 + guardMode = False + team = False + isArmed = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggleGuardMode + { + actionGroup = None + } + AGToggleTargetType + { + actionGroup = None + } + AGJettisonWeapon + { + actionGroup = None + } + AGToggleTeam + { + actionGroup = None + } + AGToggleArm + { + actionGroup = None + } + AGFire + { + actionGroup = Custom06 + } + AGFireGunsHold + { + actionGroup = None + } + AGFireGunsToggle + { + actionGroup = None + } + AGCycle + { + actionGroup = Custom07 + } + AGCycleBack + { + actionGroup = Custom08 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = RadarWarningReceiver + isEnabled = True + rwrEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWingCommander + isEnabled = True + savedWingmen = + commandSelf = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Plane - AG.craft b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Plane - AG.craft new file mode 100644 index 000000000..393145322 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Plane - AG.craft @@ -0,0 +1,10525 @@ +ship = BDA - Test Plane - AG +version = 1.3.1 +description = +type = SPH +size = 13.411171,4.38962936,12.5597649 +PART +{ + part = probeStackSmall_4291045410 + partName = Part + pos = 0.42429468,9.53027534,5.33839941 + attPos = 0,0,0 + attPos0 = 0.42429468,9.53027534,5.33839941 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 0.707106769,0,0,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bdRadome1_4291057376 + link = advSasModule_4290864070 + attN = bottom,advSasModule_4290864070 + attN = top,bdRadome1_4291057376 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleProbeControlPoint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCommand + isEnabled = True + hibernation = False + hibernateOnWarp = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + MakeReferenceToggle + { + actionGroup = None + } + HibernateToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleReactionWheel + isEnabled = True + actuatorModeCycle = 0 + authorityLimiter = 100 + stateString = Active + stagingEnabled = True + WheelState = Active + EVENTS + { + } + ACTIONS + { + CycleAction + { + actionGroup = None + } + Activate + { + actionGroup = None + } + Deactivate + { + actionGroup = None + } + Toggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSAS + isEnabled = True + standaloneToggle = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleKerbNetAccess + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OpenKerbNetAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleScienceContainer + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + CollectAllAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLogisticsConsumer + isEnabled = True + lastCheck = -1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 2250 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTCA + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + onActionUpdate + { + actionGroup = None + active = False + } + ToggleTCA + { + actionGroup = None + } + } + VSLCONFIG + { + VesselID = 00000000-0000-0000-0000-000000000000 + Name = BDA - Test Plane - AG + Enabled = False + GUIVisible = False + ActiveTab = 0 + ActionGroup = None + WarpToNode = True + AltitudeAboveTerrain = False + DesiredAltitude = 0 + VerticalCutoff = 10 + BlockThrottle = False + ControlSensitivity = 0.00999999978 + ControlTransform = 0 + SteeringGain = 1 + SteeringModifier = 1,1,1 + PitchYawLinked = True + AutoTune = True + SASIsControlled = False + SASWasEnabled = False + MaxNavSpeed = 100 + ShowPath = False + VTOLAssistON = True + AutoGear = True + AutoBrakes = True + StabilizeFlight = True + UseCPS = True + CorrectWithTranslation = True + ShowManualLimits = False + AutoStage = True + AutoParachutes = True + UseSmartEngines = False + Squad = 0 + MacroIsActive = False + EnabledTCAParts + { + } + AT + { + State = None + } + VF + { + State = None + } + CTRL + { + State = None + } + HF + { + State = None + } + BR + { + State = None + } + Nav + { + State = None + } + AP1 + { + State = None + } + AP2 + { + State = None + } + Engines + { + p = 0.400000006 + i = 0.200000003 + } + SmartEngines + { + State = None + } + Path + { + Name = + } + EnginesProfiles + { + ENGINESPROF + { + Name = Default + Active = True + Activated = False + Default = True + NumManual = 0 + OnPlanet = 2 + Stage = -1 + Level = False + SmartEngines = 0 + Groups + { + } + Single + { + 4253169137 + { + Name = J-404 "Panther" Afterburning Turbofan (Dry) + On = False + Limit = 1 + role = MAIN + } + 3040704492 + { + Name = J-404 "Panther" Afterburning Turbofan (Wet) + On = False + Limit = 1 + role = MAIN + } + 2588618808 + { + Name = J-404 "Panther" Afterburning Turbofan (Dry) + On = False + Limit = 1 + role = MAIN + } + 2272412381 + { + Name = J-404 "Panther" Afterburning Turbofan (Wet) + On = False + Limit = 1 + role = MAIN + } + } + } + } + Macros + { + type = ThrottleControlledAvionics.TCAMacroLibrary, ThrottleControlledAvionics + DB + { + } + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MechJebCore + isEnabled = True + running = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnOrbitProgradeAction + { + actionGroup = None + } + OnOrbitRetrogradeAction + { + actionGroup = None + } + OnOrbitNormalAction + { + actionGroup = None + } + OnOrbitAntinormalAction + { + actionGroup = None + } + OnOrbitRadialInAction + { + actionGroup = None + } + OnOrbitRadialOutAction + { + actionGroup = None + } + OnKillRotationAction + { + actionGroup = None + } + OnDeactivateSmartASSAction + { + actionGroup = None + } + OnPanicAction + { + actionGroup = None + } + OnTranslatronOffAction + { + actionGroup = None + } + OnTranslatronKeepVertAction + { + actionGroup = None + } + OnTranslatronZeroSpeedAction + { + actionGroup = None + } + OnTranslatronPlusOneSpeedAction + { + actionGroup = None + } + OnTranslatronMinusOneSpeedAction + { + actionGroup = None + } + OnTranslatronToggleHSAction + { + actionGroup = None + } + OnAscentAPToggleAction + { + actionGroup = None + } + } + MechJebLocalSettings + { + MechJebModuleMenu + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentGuidance + { + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleAscentNavBall + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentPathEditor + { + unlockParts = + unlockTechs = + } + MechJebModuleAttitudeAdjustment + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleCustomWindowEditor + { + unlockParts = + unlockTechs = flightControl + } + MechJebModuleDebugArrows + { + unlockParts = + unlockTechs = + } + MechJebModuleDockingAutopilot + { + forceRol = False + overrideSafeDistance = False + overrideTargetSize = False + unlockParts = + unlockTechs = + rol + { + _val = 0 + _text = 0 + } + } + MechJebModuleDockingGuidance + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleInfoItems + { + unlockParts = + unlockTechs = + } + MechJebModuleLandingAutopilot + { + deployGears = True + deployChutes = True + rcsAdjustment = True + unlockParts = + unlockTechs = + touchdownSpeed + { + _val = 0.5 + _text = 0.5 + } + limitGearsStage + { + val = 0 + _text = 0 + } + limitChutesStage + { + val = 0 + _text = 0 + } + } + MechJebModuleLandingGuidance + { + landingSiteIdx = 0 + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleLandingPredictions + { + unlockParts = + unlockTechs = + } + MechJebModuleManeuverPlanner + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleNodeEditor + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleNodeExecutor + { + unlockParts = + unlockTechs = + } + MechJebModuleRCSBalancerWindow + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleRendezvousAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleRendezvousAutopilotWindow + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleRendezvousGuidance + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleRoverController + { + ControlHeading = False + ControlSpeed = False + BrakeOnEject = False + BrakeOnEnergyDepletion = False + WarpToDaylight = True + StabilityControl = False + LimitAcceleration = False + unlockParts = + unlockTechs = + heading + { + _val = 0 + _text = 0 + } + speed + { + _val = 10 + _text = 10 + } + } + MechJebModuleRoverWindow + { + unlockParts = + unlockTechs = fieldScience + } + MechJebModuleScript + { + minifiedGUI = False + selectedSlot = 0 + activeSavepoint = -1 + unlockParts = + unlockTechs = + } + MechJebModuleSettings + { + unlockParts = + unlockTechs = + } + MechJebModuleSmartASS + { + mode = ORBITAL + target = OFF + advReference = INERTIAL + advDirection = FORWARD + forceRol = False + forcePitch = True + forceYaw = True + unlockParts = + unlockTechs = flightControl + srfHdg + { + _val = 90 + _text = 90 + } + srfPit + { + _val = 90 + _text = 90 + } + srfRol + { + _val = 0 + _text = 0 + } + srfVelYaw + { + _val = 0 + _text = 0 + } + srfVelPit + { + _val = 0 + _text = 0 + } + srfVelRol + { + _val = 0 + _text = 0 + } + rol + { + _val = 0 + _text = 0 + } + } + MechJebModuleSmartRcs + { + unlockParts = + unlockTechs = + } + MechJebModuleSpaceplaneAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleSpaceplaneGuidance + { + runwayIndex = 0 + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleStageStats + { + unlockParts = + unlockTechs = + } + MechJebModuleTargetController + { + unlockParts = + unlockTechs = + } + MechJebModuleThrustWindow + { + autostageSavedState = False + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleTranslatron + { + unlockParts = + unlockTechs = advFlightControl + trans_spd + { + _val = 0 + _text = 0 + } + } + MechJebModuleWarpHelper + { + unlockParts = + unlockTechs = advFlightControl + phaseAngle + { + _val = 0 + _text = 0 + } + } + MechJebModuleWaypointWindow + { + unlockParts = + unlockTechs = + } + MechJebModuleWaypointHelpWindow + { + unlockParts = + unlockTechs = + } + ModExtensionDemo + { + unlockParts = + unlockTechs = + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleWarpController + { + unlockParts = + unlockTechs = + } + MechJebModuleSolarPanelController + { + prev_ShouldOpenSolarPanels = False + unlockParts = + unlockTechs = + } + MechJebModuleThrustController + { + limitThrottle = False + limiterMinThrottle = False + electricThrottle = False + unlockParts = + unlockTechs = + maxThrottle + { + _val = 1 + _text = 100 + } + minThrottle + { + _val = 0.050000000000000003 + _text = 5 + } + electricThrottleLo + { + _val = 0.050000000000000003 + _text = 5 + } + electricThrottleHi + { + _val = 0.14999999999999999 + _text = 15 + } + } + MechJebModuleRCSController + { + unlockParts = + unlockTechs = + Tf + { + _val = 1 + _text = 1 + } + Kp + { + _val = 0.125 + _text = 0.125 + } + Ki + { + _val = 0.070000000000000007 + _text = 0.07 + } + Kd + { + _val = 0.53000000000000003 + _text = 0.53 + } + } + MechJebModuleRCSBalancer + { + unlockParts = + unlockTechs = + } + MechJebModuleAttitudeController + { + unlockParts = + unlockTechs = + } + MechJebModuleStagingController + { + unlockParts = + unlockTechs = + } + MechJebModuleFlightRecorder + { + markUT = 0 + deltaVExpended = 0 + dragLosses = 0 + gravityLosses = 0 + steeringLosses = 0 + markLAN = 0 + markLatitude = 0 + markLongitude = 0 + markAltitude = 0 + markBodyIndex = 1 + maxDragGees = 0 + unlockParts = + unlockTechs = + } + MechJebModuleFlightRecorderGraph + { + unlockParts = + unlockTechs = + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTripLogger + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + Log + { + flight = 0 + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 15 + maxAmount = 15 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bdRadome1_4291057376 + partName = Part + pos = 0.42429468,9.53027534,6.37660503 + attPos = 0,0,0 + attPos0 = 0,1.03819942,-1.19209211E-07 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = bottom01,probeStackSmall_4291045410 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/radome125/tex_radome125 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 320 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = advSasModule_4290864070 + partName = Part + pos = 0.42429468,9.53027534,5.03937292 + attPos = 0,0,0 + attPos0 = 0,-0.299026519,2.98023224E-08 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = mk2SpacePlaneAdapter_4291307528 + link = bahaHiddenVulcan_4291307426 + link = GearSmall_4291307354 + link = bahaCamPod_4291307102 + attN = top,probeStackSmall_4291045410 + attN = bottom,mk2SpacePlaneAdapter_4291307528 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleReactionWheel + isEnabled = True + actuatorModeCycle = 0 + authorityLimiter = 100 + stateString = Active + stagingEnabled = True + WheelState = Active + EVENTS + { + } + ACTIONS + { + CycleAction + { + actionGroup = None + } + Activate + { + actionGroup = None + } + Deactivate + { + actionGroup = None + } + Toggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 1200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = mk2SpacePlaneAdapter_4291307528 + partName = Part + pos = 0.42429468,9.53027534,3.90284348 + attPos = 0,0,0 + attPos0 = 0,-1.13652527,8.94068251E-08 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 320 + modMass = -0.0399999991 + modSize = 0,0,0 + link = MK1IntakeFuselage_4291307486 + link = bahaECMJammer_4291307014 + attN = top,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/FuelTank/mk2Adapters/mk2adapters1m + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 366.399994 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = InterstellarFuelSwitch + isEnabled = True + selectedTankSetup = 2 + configuredAmounts = 400, + configuredFlowStates = True, + selectedTankSetupTxt = LiquidFuel + configLoaded = True + initialTankSetup = LiquidFuel;Oxidizer + storedFactorMultiplier = 1 + storedVolumeMultiplier = 1 + storedMassMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = MK1IntakeFuselage_4291307486 + partName = Part + pos = 0.42429468,9.53027534,3.90284348 + attPos = -0.110681586,0.937499285,-0.991788149 + attPos0 = 0.110681601,-0.937499762,0.991788149 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = 0,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = -0.0450000055 + modSize = 0,0,0 + link = mk2CargoBayL_4291306966 + srfN = srfAttach,mk2SpacePlaneAdapter_4291307528 + attN = bottom,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAnimateHeat + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Structural/mk1Parts/Mk1Structural + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 560 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = InterstellarFuelSwitch + isEnabled = True + selectedTankSetup = 1 + configuredAmounts = 200,2,2, + configuredFlowStates = True,True,True, + selectedTankSetupTxt = LiquidFuel + configLoaded = True + initialTankSetup = IntakeAir;LiquidFuel;IntakeAtm + storedFactorMultiplier = 1 + storedVolumeMultiplier = 1 + storedMassMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 200 + maxAmount = 200 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } + RESOURCE + { + name = IntakeAir + amount = 2 + maxAmount = 2 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 2 + maxAmount = 2 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaHiddenVulcan_4291307426 + partName = Part + pos = 0.42429468,10.1492939,4.93695211 + attPos = 0.00535136461,0,0 + attPos0 = -5.21540642E-08,-0.102420636,-0.619018435 + rot = 6.48255227E-10,-1.00000012,2.08616257E-07,-1.94289029E-16 + attRot = 0,0,0,1 + attRot0 = 4.58385496E-10,-0.707106709,0.707106948,4.58385219E-10 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = False + defaultDetonationRange = 3500 + useRippleFire = True + engageEnabled = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/hiddenVulcan/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4291307354 + partName = Part + pos = 0.397938222,9.26998806,4.99207735 + attPos = 0,-2.98023224E-08,-0.343781501 + attPos0 = -0.0263563544,-0.0472954996,0.604068756 + rot = 2.08616257E-07,1.94289029E-16,-6.48255227E-10,-1.00000012 + attRot = 0,0,0,1 + attRot0 = 0.707106948,-4.58385219E-10,-4.58385496E-10,-0.707106709 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = True + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + } + LightOnAction + { + actionGroup = None + } + LightOffAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaCamPod_4291307102 + partName = Part + pos = -0.424645871,9.53027534,3.83937073 + attPos = 0.0343517065,-1.22785342,8.94069458E-08 + attPos0 = -0.883292019,0.0278530046,0 + rot = 0,0,1.00000012,0 + attRot = 8.42937027E-08,0,-0.707106829,0.707106888 + attRot0 = 0,0.707106829,0.707106829,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,advSasModule_4290864070 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTargetingCamera + isEnabled = True + cameraEnabled = False + currentFovIndex = 0 + slaveTurrets = False + CoMLock = False + groundStabilized = False + savedLat = 0 + savedLong = 0 + savedAlt = 0 + nvMode = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/targetingCam/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 4000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaECMJammer_4291307014 + partName = Part + pos = 1.2242943,9.53027534,3.72464085 + attPos = -0.442279875,-0.20732379,0 + attPos0 = 1.24227953,0.0291240215,-2.38418437E-07 + rot = 0,0,0.707106769,-0.707106888 + attRot = -7.38817718E-08,0.17364642,-0.984808147,-4.18590787E-07 + attRot0 = 0.50000006,0.49999997,0.49999997,-0.50000006 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2SpacePlaneAdapter_4291307528 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleECMJammer + isEnabled = True + jammerEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + AGDisable + { + actionGroup = None + } + AGToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/ecmJammer/tex_ecmj131 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 6000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = mk2CargoBayL_4291306966 + partName = Part + pos = 0.42429468,9.53027439,1.0903368 + attPos = 0,0,0 + attPos0 = 0,-2.8125,3.57627783E-07 + rot = 0,-0.707106829,-0.707106829,0 + attRot = 0,-0.999999881,0,0 + attRot0 = 0,1,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = mk2.1m.Bicoupler_4291306838 + link = sweptWing2_4290972792 + link = sweptWing2_4289761308 + link = BD4x1panelArmor_4291303308 + link = BD4x1panelArmor_4291303162 + link = missileController_4291303016 + link = bdPilotAI_4291302972 + link = SurfAntenna_4291302944 + attN = top,MK1IntakeFuselage_4291307486 + attN = bottom,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCargoBay + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Utility/mk2CargoBay/mk2CargoBay + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = Hangar + isEnabled = True + LaunchWithPunch = False + HangarName = Mk2 Cargo Bay CRG-08 + stagingEnabled = True + hangarState = Inactive + EVENTS + { + } + ACTIONS + { + OpenGatesAction + { + actionGroup = None + } + CloseGatesAction + { + actionGroup = None + } + ToggleGatesAction + { + actionGroup = None + } + ActivateStateAction + { + actionGroup = None + } + DeactivateStateAction + { + actionGroup = None + } + ToggleStateAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = SingleUseHangarStorage + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MultiGeometryAnimator + isEnabled = True + State = Closed + progress = 0 + StopTime = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = mk2.1m.Bicoupler_4291306838 + partName = Part + pos = 0.42429468,9.53027248,-1.72219038 + attPos = 0,0,0 + attPos0 = 0,-2.81250286,-4.76837386E-07 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,-1,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 320 + modMass = -0.0399999991 + modSize = 0,0,0 + link = turboJet_4291306780 + link = turboJet_4291306642 + link = tailfin_4291306504 + link = tailfin_4291306456 + link = delta.small_4291306408 + link = delta.small_4291306330 + link = bahaCmPod_4291306252 + link = bahaCmPod_4291306222 + link = bahaCmPod_4291306192 + link = bahaCmPod_4291306162 + link = bahaChaffPod_4291306132 + link = bahaChaffPod_4291306098 + link = bahaChaffPod_4291306064 + link = bahaChaffPod_4291306030 + attN = top,mk2CargoBayL_4291306966 + attN = bottom01,turboJet_4291306642 + attN = bottom02,turboJet_4291306780 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/FuelTank/mk2Adapters/mk2adapters1m + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 676.400024 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = InterstellarFuelSwitch + isEnabled = True + selectedTankSetup = 2 + configuredAmounts = 400, + configuredFlowStates = True, + selectedTankSetupTxt = LiquidFuel + configLoaded = True + initialTankSetup = LiquidFuel;Oxidizer + storedFactorMultiplier = 1 + storedVolumeMultiplier = 1 + storedMassMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = turboJet_4291306780 + partName = Part + pos = -0.200708479,9.53027153,-2.65969563 + attPos = 0,0,0 + attPos0 = -0.625,-0.937502503,0 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = 0 + resPri = 0 + dstg = 0 + sidx = 0 + sqor = 0 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = turboJet_4291306642 + attN = top,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGimbal + isEnabled = True + gimbalLock = False + gimbalLimiter = 100 + currentShowToggles = True + enableYaw = False + enablePitch = True + enableRoll = False + gimbalActive = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + LockAction + { + actionGroup = None + } + FreeAction + { + actionGroup = None + } + TogglePitchAction + { + actionGroup = None + } + ToggleYawAction + { + actionGroup = None + } + ToggleRollAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MultiModeEngine + isEnabled = True + runningPrimary = True + autoSwitch = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ModeAction + { + actionGroup = Custom02 + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + OnAction + { + actionGroup = Custom01 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = True + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = False + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 2000 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/JetEngines + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 2000 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TCAEngineInfo + isEnabled = True + role = 0 + group = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = turboJet_4291306642 + partName = Part + pos = 1.04929721,9.53027153,-2.65969563 + attPos = 0,0,0 + attPos0 = 0.625,-0.937502503,0 + rot = -0.707106888,0,0,-0.707106769 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = 0 + resPri = 0 + dstg = 0 + sidx = 0 + sqor = 0 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = turboJet_4291306780 + attN = top,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGimbal + isEnabled = True + gimbalLock = False + gimbalLimiter = 100 + currentShowToggles = True + enableYaw = False + enablePitch = True + enableRoll = False + gimbalActive = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + } + LockAction + { + actionGroup = None + } + FreeAction + { + actionGroup = None + } + TogglePitchAction + { + actionGroup = None + } + ToggleYawAction + { + actionGroup = None + } + ToggleRollAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MultiModeEngine + isEnabled = True + runningPrimary = True + autoSwitch = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ModeAction + { + actionGroup = Custom02 + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + OnAction + { + actionGroup = Custom01 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = True + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = False + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + } + ShutdownAction + { + actionGroup = None + } + ActivateAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 2000 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/JetEngines + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 2000 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TCAEngineInfo + isEnabled = True + role = 0 + group = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = tailfin_4291306504 + partName = Part + pos = -0.775706887,9.53027153,-2.52219486 + attPos = 0.050265789,-0.412341833,-1.13686506E-13 + attPos0 = -1.25026441,-0.387660325,0 + rot = 4.21468513E-08,0.707106769,0.707106888,0 + attRot = 0,0,0,1 + attRot0 = -2.98023224E-08,-1,-5.96046448E-08,-2.98023224E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = tailfin_4291306456 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 750 + Armor = 10 + maxHitPoints = 750 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/airplaneFins/AirplaneFins + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = tailfin_4291306456 + partName = Part + pos = 1.62429655,9.53027153,-2.52219868 + attPos = -0.0502656698,-0.412344694,-1.13686506E-13 + attPos0 = 1.25026441,-0.387660325,0 + rot = 0.707107067,3.0908641E-08,7.30554746E-08,0.70710659 + attRot = 0,0,0,1 + attRot0 = 0,-7.35136965E-08,-2.98023259E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = tailfin_4291306504 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 750 + Armor = 10 + maxHitPoints = 750 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/airplaneFins/AirplaneFins + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4291306408 + partName = Part + pos = -0.196370393,10.0033607,-1.97701597 + attPos = 0.24300468,0.244145393,0.0255527496 + attPos0 = -0.863668978,-0.498970509,-0.498639941 + rot = 0.500000358,-0.499999911,-0.499999911,0.500000119 + attRot = -0.0206821579,0.499572128,0.035822738,0.865284204 + attRot0 = -0.0107059469,0.258597523,0.0399549939,-0.965099096 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon2_4291306368 + sym = delta.small_4291306330 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4291306368 + partName = Part + pos = -0.196370155,10.9581413,-2.60202169 + attPos = 0,0,0 + attPos0 = -0.954778433,-0.625002265,5.96046448E-08 + rot = 0.5,-0.500000119,-0.500000119,0.5 + attRot = 0.707106709,0.707106709,0,0 + attRot0 = -1.05367128E-07,-5.96046448E-08,1.05367128E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4291306290 + srfN = srfAttach,delta.small_4291306408 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = False + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4291306330 + partName = Part + pos = 1.04495966,10.0033607,-1.97701788 + attPos = -0.243004799,0.244143486,0.0255527496 + attPos0 = 0.863669038,-0.498970509,-0.498639941 + rot = 0.500000119,-0.499999881,-0.500000238,0.5 + attRot = -0.0206821579,0.499572128,0.035822738,0.865284204 + attRot0 = 0,0.707106829,0,-0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon2_4291306290 + sym = delta.small_4291306408 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4291306290 + partName = Part + pos = 1.0449599,10.9581432,-2.6020236 + attPos = 0,0,0 + attPos0 = -0.95477879,-0.625003994,1.19209318E-07 + rot = 0.500000119,-0.5,-0.5,0.500000119 + attRot = 0.707106709,0.707106709,0,0 + attRot0 = 0,5.96046306E-08,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4291306368 + srfN = srfAttach,delta.small_4291306330 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = False + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaCmPod_4291306252 + partName = Part + pos = 1.55027401,9.07128906,-1.80350065 + attPos = 0,0,0 + attPos0 = 1.11864269,-0.0813107491,0.464496017 + rot = 0.656742156,0.262087435,0.674054265,-0.213660896 + attRot = 0.0294955131,0.708637536,-0.0294955727,0.70433861 + attRot0 = -0.615467966,-0.661952078,-0.291304439,-0.313305706 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306222 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4291306222 + partName = Part + pos = -0.701684594,9.07128906,-1.80349874 + attPos = 0,0,0 + attPos0 = -1.11864269,-0.0813107491,0.464496017 + rot = -0.656742156,0.262087435,0.674054265,0.213660896 + attRot = 0.0294955131,0.708637536,-0.0294955727,0.70433861 + attRot0 = 0.602746069,-0.648269236,-0.31679064,0.340716779 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306252 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4291306192 + partName = Part + pos = 1.53990781,9.08495331,-1.56550741 + attPos = 0,0,0 + attPos0 = 1.11062706,0.15667963,0.448957801 + rot = 0.660270035,0.253068328,0.676917195,-0.204409465 + attRot = 0.0198426098,0.708272815,-0.0198425669,0.705380797 + attRot0 = -0.611420691,-0.657599032,-0.29970634,-0.322342128 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306162 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4291306162 + partName = Part + pos = -0.69131887,9.08495331,-1.56550646 + attPos = 0,0,0 + attPos0 = -1.11062706,0.15667963,0.448957801 + rot = -0.660270095,0.253068209,0.676917136,0.204409391 + attRot = 0.0198426098,0.708272815,-0.0198425669,0.705380797 + attRot0 = 0.602746069,-0.648269236,-0.31679064,0.340716779 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4291306192 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306132 + partName = Part + pos = 1.50910056,9.11885643,-1.08894682 + attPos = 0.00667023659,1.90734863E-06,-0.00398445129 + attPos0 = 1.07813334,0.633237362,0.415398985 + rot = 0.656254649,0.263305932,0.680280328,-0.192921668 + attRot = 0.04573825,0.710440099,-0.0457382686,0.700778663 + attRot0 = -0.600458264,-0.667216182,-0.294845432,-0.327625871 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306098 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306098 + partName = Part + pos = -0.660511136,9.11885643,-1.08894491 + attPos = -0.0066703558,2.86102295E-06,-0.00398445129 + attPos0 = -1.07813334,0.633237362,0.415398985 + rot = -0.656254709,0.263305902,0.680280268,0.192921594 + attRot = 0.04573825,0.710440099,-0.0457382686,0.700778663 + attRot0 = 0.580008984,-0.644493341,-0.333276927,0.370330185 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306132 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306064 + partName = Part + pos = 1.52630532,9.09822655,-1.32613564 + attPos = 0.00233459473,3.81469727E-06,0.000204086304 + attPos0 = 1.09967422,0.396049023,0.431839377 + rot = 0.657037497,0.261346161,0.680853188,-0.190890521 + attRot = 0.043643862,0.710353017,-0.0436438099,0.701133966 + attRot0 = -0.599575639,-0.666235387,-0.296636194,-0.329615653 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306030 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291306030 + partName = Part + pos = -0.677716374,9.09822655,-1.32613468 + attPos = -0.00233471394,4.76837158E-06,0.000204086304 + attPos0 = -1.09967422,0.396049023,0.431839377 + rot = -0.657037556,0.261346072,0.680853009,0.190890476 + attRot = 0.043643862,0.710353017,-0.0436438099,0.701133966 + attRot0 = 0.580008984,-0.644493341,-0.333276927,0.370330185 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4291306064 + srfN = srfAttach,mk2.1m.Bicoupler_4291306838 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = Custom05 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = sweptWing2_4290972792 + partName = Part + pos = -0.656202197,9.53027439,1.49033594 + attPos = -0.172393918,0.308313549,-2.38418721E-07 + attPos0 = 1.25288868,0.0916850492,0 + rot = 0.707106888,0,4.21468513E-08,0.707106769 + attRot = 0,0,0,1 + attRot0 = 2.98023224E-08,1,-5.96046448E-08,-2.98023224E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = delta.small_4290963530 + link = GearSmall_4290886262 + link = structuralWing2_4290941810 + link = bahaS-8Launcher_4291339810 + link = bahaAdjustableRail_4291046526 + link = bahaAdjustableRail_4290588540 + link = bahaAdjustableRail_4291325548 + sym = sweptWing2_4289761308 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4290963530 + partName = Part + pos = -4.40628433,9.53027344,0.24599123 + attPos = 0,0,0 + attPos0 = -3.75007486,-1.24433625,7.26427004E-07 + rot = 0.707107067,-1.89660909E-07,-1.26440398E-07,0.70710659 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,-2.53319683E-07,1.49012802E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = StandardCtrlSrf_4290871432 + sym = delta.small_4289760992 + srfN = srfAttach,sweptWing2_4290972792 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = StandardCtrlSrf_4290871432 + partName = Part + pos = -5.3399868,9.53027534,-0.379015446 + attPos = 0,0,0 + attPos0 = -0.933689117,-0.625001431,-4.07147205E-08 + rot = 0.707106829,1.12381677E-08,-3.09086445E-08,0.707106829 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = -4.17232513E-07,2.0960826E-07,-7.45058202E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = StandardCtrlSrf_4289760942 + srfN = srfAttach,delta.small_4290963530 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = False + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 400 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4290886262 + partName = Part + pos = -1.65152407,9.53027725,0.472570896 + attPos = -0.198512137,-0.647987127,-2.8504794E-06 + attPos0 = -0.7968086,-0.369776458,1.72785121E-07 + rot = 1.1920929E-07,1.04308128E-07,1.12531453E-07,1.00000012 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = -0.707106829,1.53328713E-07,-3.6332132E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = GearSmall_4289761258 + srfN = srfAttach,sweptWing2_4290972792 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = True + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + } + LightOnAction + { + actionGroup = None + } + LightOffAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralWing2_4290941810 + partName = Part + pos = -0.656202197,9.53027344,0.235273838 + attPos = 2.38166881,-0.421416581,1.92194932E-07 + attPos0 = -2.38166881,-0.83363992,-4.25805347E-08 + rot = -0.707107067,1.89660867E-07,-2.31807618E-07,-0.70710659 + attRot = 0,0,0,1 + attRot0 = -1.78813906E-07,-7.10542651E-15,-2.68220873E-07,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon3_4290934650 + link = elevon2_4290937476 + sym = structuralWing2_4289760306 + srfN = srfAttach,sweptWing2_4290972792 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon3_4290934650 + partName = Part + pos = -1.65719938,9.53027439,-0.389734745 + attPos = 0,0,0 + attPos0 = -1.00099444,-0.62500149,8.9348049E-08 + rot = 0.707106888,-2.31807789E-07,2.31807647E-07,0.707106769 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon3_4289760214 + srfN = srfAttach,structuralWing2_4290941810 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 650 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4290937476 + partName = Part + pos = -3.50696516,9.53027344,-0.389734745 + attPos = 0,0,0 + attPos0 = -2.85075283,-0.625001609,-2.09060911E-08 + rot = 0.707106888,-2.31807789E-07,2.31807647E-07,0.707106769 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4289760256 + srfN = srfAttach,structuralWing2_4290941810 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaS-8Launcher_4291339810 + partName = Part + pos = -1.54620755,9.21123505,2.72575235 + attPos = -0.0153685808,0.191289306,0.0127838254 + attPos0 = -0.890004337,1.23541248,0.319039375 + rot = -1.1920929E-07,5.96046377E-08,-4.21468442E-08,-1.00000012 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = 0.707106829,1.23445227E-08,-2.98023135E-08,-0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaS-8Launcher_4291103730 + srfN = srfAttach,sweptWing2_4290972792 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = RocketLauncher + isEnabled = True + engageEnabled = True + engageRangeMin = 0 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/s-8Launcher/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = S-8KOMRocket + amount = 23 + maxAmount = 23 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = sweptWing2_4289761308 + partName = Part + pos = 1.50479162,9.53027439,1.49033689 + attPos = 0.172393918,0.308314025,-2.38418721E-07 + attPos0 = -1.25288868,0.0916850492,0 + rot = 1.12382352E-08,0.707106829,0.707106829,-3.09086197E-08 + attRot = 0,0,0,1 + attRot0 = 0,1.39090748E-08,2.98023117E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = delta.small_4289760992 + link = GearSmall_4289761258 + link = structuralWing2_4289760306 + link = bahaS-8Launcher_4291103730 + link = bahaAdjustableRail_4290584602 + link = bahaAdjustableRail_4290583688 + link = bahaAdjustableRail_4290516230 + sym = sweptWing2_4290972792 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = delta.small_4289760992 + partName = Part + pos = 5.25488138,9.53027344,0.24599123 + attPos = 0,0,0 + attPos0 = -3.75007486,-1.24433625,7.26427004E-07 + rot = -1.57349064E-07,0.707106709,0.707106948,-2.20569603E-07 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,-2.53319683E-07,1.49012802E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = StandardCtrlSrf_4289760942 + sym = delta.small_4290963530 + srfN = srfAttach,sweptWing2_4289761308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = StandardCtrlSrf_4289760942 + partName = Part + pos = 6.18858147,9.53027534,-0.379015446 + attPos = 0,0,0 + attPos0 = -0.933689117,-0.625001431,-4.07147205E-08 + rot = -6.18173388E-08,0.707106829,0.707106829,-1.96704608E-08 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = -4.17232513E-07,2.0960826E-07,-7.45058202E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = StandardCtrlSrf_4290871432 + srfN = srfAttach,delta.small_4289760992 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = False + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 400 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4289761258 + partName = Part + pos = 2.50011539,9.53027725,0.472570896 + attPos = -0.19851166,-0.647989035,2.66054917E-06 + attPos0 = -0.7968086,-0.369776458,1.72785121E-07 + rot = -1.1920929E-07,1.04308143E-07,1.12531438E-07,-1.00000012 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = -0.707106829,1.53328713E-07,-3.6332132E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = GearSmall_4290886262 + srfN = srfAttach,sweptWing2_4289761308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = True + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + } + LightOnAction + { + actionGroup = None + } + LightOffAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralWing2_4289760306 + partName = Part + pos = 1.50479162,9.53027439,0.235273838 + attPos = 2.38166714,-0.421417356,6.62534347E-08 + attPos0 = -2.38166714,-0.833640575,-6.62534347E-08 + rot = 2.00899038E-07,0.70710665,0.707107008,-2.2056939E-07 + attRot = 0,0,0,1 + attRot0 = -2.68220873E-07,4.44089167E-15,2.68220788E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon3_4289760214 + link = elevon2_4289760256 + sym = structuralWing2_4290941810 + srfN = srfAttach,sweptWing2_4289761308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon3_4289760214 + partName = Part + pos = 2.50579166,9.53027439,-0.389734745 + attPos = 0,0,0 + attPos0 = -1.00099444,-0.62500149,8.9348049E-08 + rot = 2.0089918E-07,0.707106829,0.707106829,-2.62716583E-07 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon3_4290934650 + srfN = srfAttach,structuralWing2_4289760306 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 650 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4289760256 + partName = Part + pos = 4.35556221,9.53027439,-0.389734745 + attPos = 0,0,0 + attPos0 = -2.85075283,-0.625001609,-2.09060911E-08 + rot = 2.0089918E-07,0.707106829,0.707106829,-2.62716583E-07 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = 1.19209275E-07,2.98023224E-08,-2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4290937476 + srfN = srfAttach,structuralWing2_4289760306 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = SyncModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + } + ActionExtend + { + actionGroup = None + } + ActionRetract + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaS-8Launcher_4291103730 + partName = Part + pos = 2.39479876,9.21123409,2.72575235 + attPos = -0.0153685808,0.191289306,0.0127838254 + attPos0 = -0.890004456,1.23541057,-0.319039524 + rot = -2.08616257E-07,-5.9604659E-08,4.21468442E-08,-1.00000012 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = -6.07109172E-08,0.707106888,0.70710665,1.85640907E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaS-8Launcher_4291339810 + srfN = srfAttach,sweptWing2_4289761308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = RocketLauncher + isEnabled = True + engageEnabled = True + engageRangeMin = 0 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/s-8Launcher/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = S-8KOMRocket + amount = 23 + maxAmount = 23 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = BD4x1panelArmor_4291303308 + partName = Part + pos = -0.173249394,9.71263123,1.13073254 + attPos = -0.152653575,-0.899919868,0.221671417 + attPos0 = 0.750196397,0.940315127,-0.0393154733 + rot = 0.51291728,-0.486739963,-0.486740381,0.51291728 + attRot = 0,0,0,1 + attRot0 = 8.94069672E-08,-0.725374341,-5.96046448E-08,-0.688354611 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = UniversalAmmoBoxBDA_4291303198 + link = bahaAdjustableRail_4291303106 + link = bahaAdjustableRail_4291014304 + sym = BD4x1panelArmor_4291303162 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 13000 + Armor = 150 + maxHitPoints = 0 + ArmorThickness = 150 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/ArmorPlate/armorpanelNRM + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleHullBreach + isEnabled = True + hydroExplosive = False + hull = False + crushDepth = 200 + DepthCharge = False + partDebug = True + flowMultiplier = 1 + crushable = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = UniversalAmmoBoxBDA_4291303198 + partName = Part + pos = 0.0790378451,9.86736488,1.98109007 + attPos = 0,0,0 + attPos0 = -0.141316891,0.850357771,-0.260038227 + rot = -0.0261769462,0.999657512,5.96046448E-08,-3.37138772E-07 + attRot = 0,0,0,1 + attRot0 = -0.49999994,0.5,-0.50000006,-0.49999994 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = UniversalAmmoBoxBDA_4291303052 + srfN = srfAttach,BD4x1panelArmor_4291303308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FSfuelSwitch + isEnabled = True + selectedTankSetup = 7 + hasLaunched = False + configLoaded = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1 + defaultScale = 1 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaAdjustableRail_4291303106 + partName = Part + pos = 0.00758776069,9.65159512,1.31706762 + attPos = -0.00533951074,-0.145290554,-0.10195677 + attPos0 = 0.0704157501,0.186335251,-0.177394301 + rot = 1.54972076E-06,-1.06170774E-07,-0.0261766296,-0.999657452 + attRot = 0,0,0,1 + attRot0 = 0.500001073,-0.499998927,-0.500000656,-0.499999374 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaJdamMk83_4291302876 + sym = bahaAdjustableRail_4291028776 + srfN = srfAttach,BD4x1panelArmor_4291303308 + attN = bottom,bahaJdamMk83_4291302876 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaJdamMk83_4291302876 + partName = Part + pos = 0.0268354714,9.28432274,1.05039072 + attPos = 0,0,0 + attPos0 = -1.47023428E-07,-0.367774695,-0.266678125 + rot = 1.49011612E-06,-2.31899321E-07,-0.0261767134,-0.999657452 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = -8.94069601E-08,1.49011598E-07,-1.49011594E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaJdamMk83_4291028712 + attN = top,bahaAdjustableRail_4291303106 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = Mk83 JDAM + maxStaticLaunchRange = 5000 + minStaticLaunchRange = 10 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 1 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 10 + engageRangeMax = 5000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291014304 + partName = Part + pos = -0.413873821,9.62950611,1.14361048 + attPos = -0.00533951074,-0.145290554,-0.10195677 + attPos0 = 0.0704168677,0.0128778759,0.244644284 + rot = 6.2584877E-07,-1.05239451E-07,-0.02617722,-0.999657512 + attRot = 0,0,0,1 + attRot0 = 0.500000358,-0.499999642,-0.500000477,-0.499999553 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaMk82BombBrake_4291014228 + sym = bahaAdjustableRail_4291027724 + srfN = srfAttach,BD4x1panelArmor_4291303308 + attN = bottom,bahaMk82BombBrake_4291014228 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaMk82BombBrake_4291014228 + partName = Part + pos = -0.396792203,9.30357742,1.01041126 + attPos = 0,0,0 + attPos0 = -2.9802257E-07,-0.326373845,-0.133199662 + rot = 9.53674316E-07,-8.38190317E-08,-0.0261772405,-0.999657512 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = -1.1920929E-07,1.93715096E-07,-1.04308128E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaMk82BombBrake_4291014530 + attN = top,bahaAdjustableRail_4291014304 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 2 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = Mk82 SnakeEye + maxStaticLaunchRange = 5000 + minStaticLaunchRange = 10 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0.5 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 10 + engageRangeMax = 5000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 133.5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = BD4x1panelArmor_4291303162 + partName = Part + pos = 1.02183902,9.71262932,1.13073254 + attPos = 0.152653337,-0.899919868,0.221670464 + attPos0 = -0.750196397,0.940315127,-0.0393154733 + rot = -0.51291728,-0.486739933,-0.486740232,-0.512917399 + attRot = 0,0,0,1 + attRot0 = -1.1920929E-07,-0.72537446,-2.98023224E-08,0.688354552 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = UniversalAmmoBoxBDA_4291303052 + link = bahaAdjustableRail_4291028776 + link = bahaAdjustableRail_4291027724 + sym = BD4x1panelArmor_4291303308 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 13000 + Armor = 150 + maxHitPoints = 0 + ArmorThickness = 150 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/ArmorPlate/armorpanelNRM + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleHullBreach + isEnabled = True + hydroExplosive = False + hull = False + crushDepth = 200 + DepthCharge = False + partDebug = True + flowMultiplier = 1 + crushable = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = UniversalAmmoBoxBDA_4291303052 + partName = Part + pos = 0.769552112,9.86736488,1.98109007 + attPos = 0,0,0 + attPos0 = 0.14131777,0.850357831,-0.260038644 + rot = 0.0261769872,0.999657393,0,1.2665987E-07 + attRot = 0,0,0,1 + attRot0 = -0.49999994,-0.50000006,0.50000006,-0.50000006 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = UniversalAmmoBoxBDA_4291303198 + srfN = srfAttach,BD4x1panelArmor_4291303162 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FSfuelSwitch + isEnabled = True + selectedTankSetup = 7 + hasLaunched = False + configLoaded = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1 + defaultScale = 1 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaAdjustableRail_4291028776 + partName = Part + pos = 0.841001868,9.65159607,1.31706667 + attPos = -0.00533951074,-0.145290554,-0.10195677 + attPos0 = -0.0704149231,0.186335236,-0.177394643 + rot = 1.49011612E-06,3.6880374E-07,0.0261765774,-0.999657452 + attRot = 0,0,0,1 + attRot0 = -0.500001073,-0.499998957,-0.500000417,0.499999583 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaJdamMk83_4291028712 + sym = bahaAdjustableRail_4291303106 + srfN = srfAttach,BD4x1panelArmor_4291303162 + attN = bottom,bahaJdamMk83_4291028712 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaJdamMk83_4291028712 + partName = Part + pos = 0.821754694,9.28432369,1.05039072 + attPos = 0,0,0 + attPos0 = -1.47023428E-07,-0.367774695,-0.266678125 + rot = 1.40070915E-06,4.9546361E-07,0.0261765774,-0.999657393 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = -8.94069601E-08,1.49011598E-07,-1.49011594E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaJdamMk83_4291302876 + attN = top,bahaAdjustableRail_4291028776 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = Mk83 JDAM + maxStaticLaunchRange = 5000 + minStaticLaunchRange = 10 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 1 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 10 + engageRangeMax = 5000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291027724 + partName = Part + pos = 1.26246262,9.62950706,1.14361 + attPos = -0.00533951074,-0.145290554,-0.10195677 + attPos0 = -0.0704158843,0.0128778564,0.244644105 + rot = 1.04308128E-06,3.4738332E-07,0.0261773132,-0.999657393 + attRot = 0,0,0,1 + attRot0 = -0.500000536,-0.499999613,-0.500000417,0.499999613 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaMk82BombBrake_4291014530 + sym = bahaAdjustableRail_4291014304 + srfN = srfAttach,BD4x1panelArmor_4291303162 + attN = bottom,bahaMk82BombBrake_4291014530 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaMk82BombBrake_4291014530 + partName = Part + pos = 1.24538112,9.30357838,1.01041126 + attPos = 0,0,0 + attPos0 = -2.9802257E-07,-0.326373845,-0.133199662 + rot = 8.94069672E-07,1.58324838E-07,0.0261774622,-0.999657452 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = -1.1920929E-07,1.93715096E-07,-1.04308128E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaMk82BombBrake_4291014228 + attN = top,bahaAdjustableRail_4291027724 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 2 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = Mk82 SnakeEye + maxStaticLaunchRange = 5000 + minStaticLaunchRange = 10 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0.5 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 10 + engageRangeMax = 5000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 133.5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileController_4291303016 + partName = Part + pos = 0.42429468,10.2255268,2.6788373 + attPos = 0,0,0 + attPos0 = 0,1.5884949,0.695250511 + rot = -6.58544219E-10,-1.00000012,1.1920929E-07,1.11022302E-16 + attRot = 0,0,0,1 + attRot0 = 0.707106888,-4.65660954E-10,4.65661121E-10,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileFire + isEnabled = True + weaponIndex = 0 + targetScanInterval = 3 + fireBurstLength = 0 + guardAngle = 360 + guardRange = 10000 + gunRange = 2500 + maxMissilesOnTarget = 1 + guardMode = False + team = False + isArmed = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggleGuardMode + { + actionGroup = None + } + AGToggleTargetType + { + actionGroup = None + } + AGJettisonWeapon + { + actionGroup = None + } + AGToggleTeam + { + actionGroup = None + } + AGToggleArm + { + actionGroup = None + } + AGFire + { + actionGroup = Custom06 + } + AGFireGunsHold + { + actionGroup = None + } + AGFireGunsToggle + { + actionGroup = None + } + AGCycle + { + actionGroup = Custom07 + } + AGCycleBack + { + actionGroup = Custom08 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = RadarWarningReceiver + isEnabled = True + rwrEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWingCommander + isEnabled = True + savedWingmen = + commandSelf = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bdPilotAI_4291302972 + partName = Part + pos = 0.42429468,10.2810154,1.73860788 + attPos = 0,0,0 + attPos0 = 0,0.648269176,0.750738859 + rot = -6.58544219E-10,-1.00000012,1.1920929E-07,1.11022302E-16 + attRot = 0,0,0,1 + attRot0 = 0.707106888,-4.65660954E-10,4.65661121E-10,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDModulePilotAI + isEnabled = True + pilotEnabled = False + defaultAltitude = 2000 + minAltitude = 500 + steerMult = 8 + pitchKiAdjust = 0 + maxSteer = 1 + steerDamping = 3 + maxSpeed = 800 + takeOffSpeed = 90 + minSpeed = 80 + idleSpeed = 120 + maxAllowedGForce = 18 + maxAllowedAoA = 45 + standbyMode = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGActivatePilot + { + actionGroup = None + } + AGDeactivatePilot + { + actionGroup = None + } + AGTogglePilot + { + actionGroup = Custom10 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = SurfAntenna_4291302944 + partName = Part + pos = 0.42429468,10.3104229,0.384404182 + attPos = 0,0,0 + attPos0 = 0,-0.705931187,0.780145407 + rot = 5.96046448E-08,0.707106829,-5.96046448E-08,-0.707106829 + attRot = 0,0.707106709,0,0.707106709 + attRot0 = -0.50000006,-0.49999997,-0.50000006,-0.49999997 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,mk2CargoBayL_4291306966 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291046526 + partName = Part + pos = -4.07375193,9.48827553,1.22997904 + attPos = 0,0,0 + attPos0 = -3.41754436,-0.260355175,0.0419986919 + rot = 1.1920929E-07,-8.94069814E-08,4.21468656E-08,1.00000012 + attRot = 0,0,-0.707106709,-0.707106709 + attRot0 = -0.707106829,-3.34179475E-08,5.08757587E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAGM-65_4291354930 + sym = bahaAdjustableRail_4290584602 + srfN = srfAttach,sweptWing2_4290972792 + attN = bottom,bahaAGM-65_4291354930 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0800000131 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4291354930 + partName = Part + pos = -4.07375002,9.18840599,1.34678173 + attPos = 0,0,0 + attPos0 = 4.92517358E-07,-0.379873455,0.11680077 + rot = -1.1920929E-07,8.94069956E-08,-4.21468762E-08,-1.00000012 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,-1.77635599E-15,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAGM-65_4290584538 + attN = top,bahaAdjustableRail_4291046526 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 85.5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4290584602 + partName = Part + pos = 4.92234421,9.48827553,1.22997856 + attPos = 0,0,0 + attPos0 = -3.41753721,-0.260356456,-0.0419989079 + rot = -2.08616257E-07,-8.9406953E-08,4.21468478E-08,-1.00000012 + attRot = 0,0,-0.707106709,-0.707106709 + attRot0 = -8.17843357E-08,0.707106888,0.70710665,-2.50931809E-09 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAGM-65_4290584538 + sym = bahaAdjustableRail_4291046526 + srfN = srfAttach,sweptWing2_4289761308 + attN = bottom,bahaAGM-65_4290584538 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0800000131 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4290584538 + partName = Part + pos = 4.9223423,9.18840599,1.34678125 + attPos = 0,0,0 + attPos0 = 4.92517358E-07,-0.379873455,0.11680077 + rot = -2.08616257E-07,-8.94069672E-08,4.21468656E-08,-1.00000012 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,-1.77635599E-15,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAGM-65_4291354930 + attN = top,bahaAdjustableRail_4290584602 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 85.5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4290588540 + partName = Part + pos = -3.27731967,9.48827553,1.76297688 + attPos = 0,0,0 + attPos0 = -2.62111378,0.272640973,0.041998852 + rot = 1.1920929E-07,-8.94069814E-08,4.21468656E-08,1.00000012 + attRot = 0,0,-0.707106709,-0.707106709 + attRot0 = -0.707106829,-3.34179475E-08,5.08757587E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAGM-65_4290588476 + sym = bahaAdjustableRail_4290583688 + srfN = srfAttach,sweptWing2_4290972792 + attN = bottom,bahaAGM-65_4290588476 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0800000131 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4290588476 + partName = Part + pos = -3.27731776,9.18840599,1.8797791 + attPos = 0,0,0 + attPos0 = 4.92517358E-07,-0.379873455,0.11680077 + rot = -1.1920929E-07,8.94069956E-08,-4.21468762E-08,-1.00000012 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,-1.77635599E-15,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAGM-65_4290583618 + attN = top,bahaAdjustableRail_4290588540 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 85.5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4290583688 + partName = Part + pos = 4.12591124,9.48827553,1.76297641 + attPos = 0,0,0 + attPos0 = -2.62110829,0.272639394,-0.041999124 + rot = -2.08616257E-07,-8.9406953E-08,4.21468478E-08,-1.00000012 + attRot = 0,0,-0.707106709,-0.707106709 + attRot0 = -8.17843357E-08,0.707106888,0.70710665,-2.50931809E-09 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAGM-65_4290583618 + sym = bahaAdjustableRail_4290588540 + srfN = srfAttach,sweptWing2_4289761308 + attN = bottom,bahaAGM-65_4290583618 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.0800000131 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4290583618 + partName = Part + pos = 4.12590885,9.18840599,1.8797791 + attPos = 0,0,0 + attPos0 = 4.92517358E-07,-0.379873455,0.11680077 + rot = -2.08616257E-07,-8.94069672E-08,4.21468656E-08,-1.00000012 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,-1.77635599E-15,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaAGM-65_4290588476 + attN = top,bahaAdjustableRail_4290583688 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 0 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 85.5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4291325548 + partName = Part + pos = -2.46529746,9.48827553,2.25162387 + attPos = -0.00533951074,-0.145290554,-0.10195677 + attPos0 = -1.80909252,0.761286795,0.0419987887 + rot = 1.1920929E-07,-8.94069814E-08,4.21468656E-08,1.00000012 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = -0.707106829,-3.34179475E-08,5.08757587E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaClusterBomb_4291481322 + sym = bahaAdjustableRail_4290516230 + srfN = srfAttach,sweptWing2_4290972792 + attN = bottom,bahaClusterBomb_4291481322 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaClusterBomb_4291481322 + partName = Part + pos = -2.46529746,9.04839897,2.26842475 + attPos = 0,0,0 + attPos0 = -3.42432616E-09,-0.439874083,0.0168002788 + rot = 0,-8.90674698E-08,4.2146862E-08,1.00000012 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = -8.94069672E-08,3.39480222E-10,-8.8817842E-16,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaClusterBomb_4290516166 + attN = top,bahaAdjustableRail_4291325548 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 2 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = CBU-87 + maxStaticLaunchRange = 5000 + minStaticLaunchRange = 10 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0.5 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 10 + engageRangeMax = 5000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 12 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ClusterBomb + isEnabled = True + deployAltitude = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4290516230 + partName = Part + pos = 3.31388855,9.48827553,2.25162363 + attPos = -0.00533951074,-0.145290554,-0.10195677 + attPos0 = -1.80908883,0.761284888,-0.0419991016 + rot = 2.08616257E-07,8.9406953E-08,-4.21468478E-08,1.00000012 + attRot = 0,0,0.707106709,0.707106709 + attRot0 = 8.17843357E-08,-0.707106888,-0.70710665,2.50931809E-09 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaClusterBomb_4290516166 + sym = bahaAdjustableRail_4291325548 + srfN = srfAttach,sweptWing2_4289761308 + attN = bottom,bahaClusterBomb_4290516166 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.11999999 + railLength = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaClusterBomb_4290516166 + partName = Part + pos = 3.31388927,9.04839802,2.26842427 + attPos = 0,0,0 + attPos0 = -3.42432616E-09,-0.439874083,0.0168002788 + rot = 1.1920929E-07,8.90674698E-08,-4.21468549E-08,1.00000012 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = -8.94069672E-08,3.39480222E-10,-8.8817842E-16,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaClusterBomb_4291481322 + attN = top,bahaAdjustableRail_4290516230 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 2 + cruiseAltitude = 800 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = CBU-87 + maxStaticLaunchRange = 5000 + minStaticLaunchRange = 10 + maxOffBoresight = 360 + DetonationDistance = 0 + dropTime = 0.5 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 10 + engageRangeMax = 5000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 12 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + } + DetonateAG + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ClusterBomb + isEnabled = True + deployAltitude = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Platform - Missile.craft b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Platform - Missile.craft new file mode 100644 index 000000000..9741495e8 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Platform - Missile.craft @@ -0,0 +1,6692 @@ +ship = BDA - Test Platform - Missile +version = 1.3.0 +description = +type = SPH +size = 15.917017,9.33362579,11.4446468 +PART +{ + part = sasModule_4284270764 + partName = Part + pos = -1.9087882,9.05923176,0.130169347 + attPos = 0,0,0 + attPos0 = 1.56324098E-14,-1.56634903,1.78813906E-07 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,1 + attRot0 = -1,0,4.37113883E-08,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527766 + attN = bottom,trussPiece3x_4294527766 + attN = top,probeCoreOcto2_4284205004 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleReactionWheel + isEnabled = True + actuatorModeCycle = 1 + authorityLimiter = 100 + stateString = Active + stagingEnabled = True + WheelState = Active + EVENTS + { + } + ACTIONS + { + CycleAction + { + actionGroup = None + } + Activate + { + actionGroup = None + } + Deactivate + { + actionGroup = None + } + Toggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 0.625 + defaultScale = 0.625 + defaultTransformScale = (0.5, 0.5, 0.5) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = probeCoreOcto2_4284205004 + partName = Part + pos = -1.9087882,9.05923176,0.282343626 + attPos = 0,0,0 + attPos0 = -1.9087882,9.05923176,0.282343626 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,0.999999881 + attRot0 = 0.707106769,0,0,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = sasModule_4284270764 + attN = bottom,sasModule_4284270764 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleCommand + isEnabled = True + hibernation = False + hibernateOnWarp = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + HibernateToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSAS + isEnabled = True + standaloneToggle = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleKerbNetAccess + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OpenKerbNetAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 1479.99988 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTCA + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + onActionUpdate + { + actionGroup = None + active = False + } + ToggleTCA + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MechJebCore + isEnabled = True + running = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnOrbitProgradeAction + { + actionGroup = None + } + OnOrbitRetrogradeAction + { + actionGroup = None + } + OnOrbitNormalAction + { + actionGroup = None + } + OnOrbitAntinormalAction + { + actionGroup = None + } + OnOrbitRadialInAction + { + actionGroup = None + } + OnOrbitRadialOutAction + { + actionGroup = None + } + OnKillRotationAction + { + actionGroup = None + } + OnDeactivateSmartASSAction + { + actionGroup = None + } + OnPanicAction + { + actionGroup = None + } + OnTranslatronOffAction + { + actionGroup = None + } + OnTranslatronKeepVertAction + { + actionGroup = None + } + OnTranslatronZeroSpeedAction + { + actionGroup = None + } + OnTranslatronPlusOneSpeedAction + { + actionGroup = None + } + OnTranslatronMinusOneSpeedAction + { + actionGroup = None + } + OnTranslatronToggleHSAction + { + actionGroup = None + } + OnAscentAPToggleAction + { + actionGroup = None + } + } + MechJebLocalSettings + { + MechJebModuleMenu + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentGuidance + { + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleAscentNavBall + { + unlockParts = + unlockTechs = + } + MechJebModuleAscentPathEditor + { + unlockParts = + unlockTechs = + } + MechJebModuleAttitudeAdjustment + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleCustomWindowEditor + { + unlockParts = + unlockTechs = flightControl + } + MechJebModuleDebugArrows + { + unlockParts = + unlockTechs = + } + MechJebModuleDockingAutopilot + { + forceRol = False + overrideSafeDistance = False + overrideTargetSize = False + unlockParts = + unlockTechs = + rol + { + _val = 0 + _text = 0 + } + } + MechJebModuleDockingGuidance + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleInfoItems + { + unlockParts = + unlockTechs = + } + MechJebModuleLandingAutopilot + { + deployGears = True + deployChutes = True + rcsAdjustment = True + unlockParts = + unlockTechs = + touchdownSpeed + { + _val = 0.5 + _text = 0.5 + } + limitGearsStage + { + val = 0 + _text = 0 + } + limitChutesStage + { + val = 0 + _text = 0 + } + } + MechJebModuleLandingGuidance + { + landingSiteIdx = 0 + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleLandingPredictions + { + unlockParts = + unlockTechs = + } + MechJebModuleManeuverPlanner + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleNodeEditor + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleNodeExecutor + { + unlockParts = + unlockTechs = + } + MechJebModuleRCSBalancerWindow + { + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleRendezvousAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleRendezvousAutopilotWindow + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleRendezvousGuidance + { + unlockParts = + unlockTechs = advUnmanned + } + MechJebModuleRoverController + { + ControlHeading = False + ControlSpeed = False + BrakeOnEject = False + BrakeOnEnergyDepletion = False + WarpToDaylight = True + StabilityControl = False + LimitAcceleration = False + unlockParts = + unlockTechs = + heading + { + _val = 0 + _text = 0 + } + speed + { + _val = 10 + _text = 10 + } + } + MechJebModuleRoverWindow + { + unlockParts = + unlockTechs = fieldScience + } + MechJebModuleScript + { + minifiedGUI = False + selectedSlot = 0 + activeSavepoint = -1 + unlockParts = + unlockTechs = + } + MechJebModuleSettings + { + unlockParts = + unlockTechs = + } + MechJebModuleSmartASS + { + mode = ORBITAL + target = OFF + advReference = INERTIAL + advDirection = FORWARD + forceRol = False + forcePitch = True + forceYaw = True + unlockParts = + unlockTechs = flightControl + srfHdg + { + _val = 90 + _text = 90 + } + srfPit + { + _val = 90 + _text = 90 + } + srfRol + { + _val = 0 + _text = 0 + } + srfVelYaw + { + _val = 0 + _text = 0 + } + srfVelPit + { + _val = 0 + _text = 0 + } + srfVelRol + { + _val = 0 + _text = 0 + } + rol + { + _val = 0 + _text = 0 + } + } + MechJebModuleSmartRcs + { + unlockParts = + unlockTechs = + } + MechJebModuleSpaceplaneAutopilot + { + unlockParts = + unlockTechs = + } + MechJebModuleSpaceplaneGuidance + { + runwayIndex = 0 + unlockParts = + unlockTechs = unmannedTech + } + MechJebModuleStageStats + { + unlockParts = + unlockTechs = + } + MechJebModuleTargetController + { + unlockParts = + unlockTechs = + } + MechJebModuleThrustWindow + { + autostageSavedState = False + unlockParts = + unlockTechs = advFlightControl + } + MechJebModuleTranslatron + { + unlockParts = + unlockTechs = advFlightControl + trans_spd + { + _val = 0 + _text = 0 + } + } + MechJebModuleWarpHelper + { + unlockParts = + unlockTechs = advFlightControl + phaseAngle + { + _val = 0 + _text = 0 + } + } + MechJebModuleWaypointWindow + { + unlockParts = + unlockTechs = + } + MechJebModuleWaypointHelpWindow + { + unlockParts = + unlockTechs = + } + ModExtensionDemo + { + unlockParts = + unlockTechs = + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleCustomInfoWindow + { + } + MechJebModuleWarpController + { + unlockParts = + unlockTechs = + } + MechJebModuleSolarPanelController + { + prev_ShouldOpenSolarPanels = False + unlockParts = + unlockTechs = + } + MechJebModuleThrustController + { + limitThrottle = False + limiterMinThrottle = False + electricThrottle = False + unlockParts = + unlockTechs = + maxThrottle + { + _val = 1 + _text = 100 + } + minThrottle + { + _val = 0.050000000000000003 + _text = 5 + } + electricThrottleLo + { + _val = 0.050000000000000003 + _text = 5 + } + electricThrottleHi + { + _val = 0.14999999999999999 + _text = 15 + } + } + MechJebModuleRCSController + { + unlockParts = + unlockTechs = + Tf + { + _val = 1 + _text = 1 + } + Kp + { + _val = 0.125 + _text = 0.125 + } + Ki + { + _val = 0.070000000000000007 + _text = 0.07 + } + Kd + { + _val = 0.53000000000000003 + _text = 0.53 + } + } + MechJebModuleRCSBalancer + { + unlockParts = + unlockTechs = + } + MechJebModuleAttitudeController + { + unlockParts = + unlockTechs = + } + MechJebModuleStagingController + { + unlockParts = + unlockTechs = + } + MechJebModuleFlightRecorder + { + markUT = 0 + deltaVExpended = 0 + dragLosses = 0 + gravityLosses = 0 + steeringLosses = 0 + markLAN = 0 + markLatitude = 0 + markLongitude = 0 + markAltitude = 0 + markBodyIndex = 1 + maxDragGees = 0 + unlockParts = + unlockTechs = + } + MechJebModuleFlightRecorderGraph + { + unlockParts = + unlockTechs = + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTripLogger + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + Log + { + flight = 0 + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 5 + maxAmount = 5 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = trussPiece3x_4294527766 + partName = Part + pos = -1.9087882,9.0592308,-1.43619597 + attPos = -1.57232896E-14,-0.0202863198,0.238357604 + attPos0 = 0,-1.56634903,1.86723398E-07 + rot = 0.707106829,0,0,-0.707106829 + attRot = 0.999999881,0,0,0 + attRot0 = 1,0,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527742 + link = structuralPanel2_4294527598 + link = structuralPanel2_4294527574 + attN = bottom,sasModule_4284270764 + attN = top,trussPiece3x_4294527742 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527742 + partName = Part + pos = -1.9087882,9.0592289,-3.53619766 + attPos = 0,-0.850475311,1.28207176E-07 + attPos0 = 0,2.95047593,-3.51724196E-07 + rot = 0.707106829,0,0,-0.707106829 + attRot = 0.999999881,0,0,0 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527718 + link = structuralPanel2_4294527646 + link = structuralPanel2_4294527622 + attN = bottom,trussPiece3x_4294527766 + attN = top,trussPiece3x_4294527718 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527718 + partName = Part + pos = -1.9087882,9.0592289,-5.53619957 + attPos = 0,-0.950474501,-1.25112621E-07 + attPos0 = 0,2.95047688,-3.51724196E-07 + rot = 0.707106829,0,0,-0.707106829 + attRot = 0.999999881,0,0,0 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294527694 + link = structuralPanel2_4294527670 + attN = bottom,trussPiece3x_4294527742 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527694 + partName = Part + pos = -0.908787489,9.38470268,-5.41878223 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1,-0.117423102,0.325475812 + rot = -2.38418579E-07,0,0,1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -0.70710659,0,0,-0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294527422 + link = trussPiece3x_4294527278 + link = rtg_4294526664 + link = missileController_4294526838 + sym = structuralPanel2_4294527670 + srfN = srfAttach,trussPiece3x_4294527718 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527670 + partName = Part + pos = -2.9087894,9.38470268,-5.41878128 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = -1,-0.117423996,0.325475812 + rot = 1.0658141E-14,1.00000012,-2.38418579E-07,-4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 3.0908609E-08,-0.707107008,-0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294527398 + link = rtg_4294526696 + sym = structuralPanel2_4294527694 + srfN = srfAttach,trussPiece3x_4294527718 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527646 + partName = Part + pos = -0.908787489,9.38479233,-3.44725728 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.5,-0.0889410973,0.32556349 + rot = -2.38418579E-07,0,0,1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -0.70710659,0,0,-0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294527374 + link = ksp.r.largeBatteryPack_4294526376 + link = ksp.r.largeBatteryPack_4294526328 + sym = structuralPanel2_4294527622 + srfN = srfAttach,trussPiece3x_4294527742 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527622 + partName = Part + pos = -2.90878749,9.38479233,-3.44725633 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = -1.5,-0.0889415666,0.32556349 + rot = 1.0658141E-14,1.00000012,-2.38418579E-07,-4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 3.0908609E-08,-0.707107008,-0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294527350 + link = ksp.r.largeBatteryPack_4294526400 + link = ksp.r.largeBatteryPack_4294526352 + sym = structuralPanel2_4294527646 + srfN = srfAttach,trussPiece3x_4294527742 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527598 + partName = Part + pos = -0.908787489,9.38421631,-1.43568683 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.5,-0.000504255295,0.324986488 + rot = -2.38418579E-07,0,0,1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -0.70710659,0,0,-0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294527326 + sym = structuralPanel2_4294527574 + srfN = srfAttach,trussPiece3x_4294527766 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527574 + partName = Part + pos = -2.90878749,9.38421631,-1.43568683 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = -1.5,-0.000504493713,0.324986488 + rot = 1.0658141E-14,1.00000012,-2.38418579E-07,-4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 3.0908609E-08,-0.707107008,-0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294527302 + link = largeAdapter_4294515742 + sym = structuralPanel2_4294527598 + srfN = srfAttach,trussPiece3x_4294527766 + attN = top,largeAdapter_4294515742 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527422 + partName = Part + pos = 1.08588696,9.401371,-5.41878796 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.99201012,0.0250024796,-1.89840705E-06 + rot = 1.00000012,0,0,5.96046448E-07 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = 1,0,0,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527150 + link = structuralPanel2_4294525944 + link = trussPiece3x_4294486074 + sym = structuralPanel2_4294527398 + srfN = srfAttach,structuralPanel2_4294527694 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527398 + partName = Part + pos = -4.90348625,9.401371,-5.41878605 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.99201012,0.0250024796,2.1540161E-06 + rot = -4.37114309E-08,5.96046448E-07,1.00000012,-3.55271368E-14 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = -1,2.36533898E-16,-8.74227766E-08,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527126 + link = structuralPanel2_4294525866 + link = trussPiece3x_4294479658 + sym = structuralPanel2_4294527422 + srfN = srfAttach,structuralPanel2_4294527670 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527374 + partName = Part + pos = 1.05031013,9.40146065,-3.44725919 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.93864489,0.0250024796,-9.4473279E-07 + rot = 1.00000012,0,0,5.96046448E-07 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = 1,0,0,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294526100 + sym = structuralPanel2_4294527350 + srfN = srfAttach,structuralPanel2_4294527646 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527350 + partName = Part + pos = -4.86790752,9.40146065,-3.44725823 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.93864608,0.0250024796,1.19567596E-06 + rot = -4.37114309E-08,5.96046448E-07,1.00000012,-3.55271368E-14 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = -1,2.36533898E-16,-8.74227766E-08,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294526022 + sym = structuralPanel2_4294527374 + srfN = srfAttach,structuralPanel2_4294527622 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527326 + partName = Part + pos = 1.0801487,9.40088463,-1.43568802 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = -1.00000012,0,0,-5.96046448E-07 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527102 + link = structuralPanel2_4294526304 + sym = structuralPanel2_4294527302 + srfN = srfAttach,structuralPanel2_4294527598 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294527302 + partName = Part + pos = -4.89774513,9.40088463,-1.43568778 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,2.45914691E-07 + rot = -4.37114309E-08,5.96046448E-07,1.00000012,-3.55271368E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,2.36533898E-16,-8.74227766E-08,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527078 + link = structuralPanel2_4294526202 + sym = structuralPanel2_4294527326 + srfN = srfAttach,structuralPanel2_4294527574 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527278 + partName = Part + pos = -1.92894602,10.8766193,-6.0077858 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = -1.53023696,1.50023997,-0.883486271 + rot = 5.96046448E-07,0,0,-1.00000012 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.67343609E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294527254 + srfN = srfAttach,structuralPanel2_4294527694 + attN = top,trussPiece3x_4294527254 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527254 + partName = Part + pos = -1.92894602,13.8271008,-6.00779247 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0,2.95047808,-3.2976601E-07 + rot = -2.38418579E-07,0,0,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = -4.76837101E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaFlirBall_4294527230 + link = LgRadialSolarPanel_4294527054 + link = LgRadialSolarPanel_4294527000 + link = LgRadialSolarPanel_4294526946 + link = LgRadialSolarPanel_4294526892 + srfN = srfAttach,structuralPanel2_4294527694 + attN = bottom,trussPiece3x_4294527278 + attN = top,bahaFlirBall_4294527230 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaFlirBall_4294527230 + partName = Part + pos = -1.92894602,15.3804836,-6.00779533 + attPos = 0,0,0 + attPos0 = 0,1.55337095,-1.00847001E-06 + rot = 0.707106829,0,0,-0.707106948 + attRot = 0.999999881,0,0,0 + attRot0 = 0.707106829,0,0,-0.707106888 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,trussPiece3x_4294527254 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTargetingCamera + isEnabled = True + cameraEnabled = False + currentFovIndex = 0 + slaveTurrets = False + CoMLock = False + groundStabilized = False + savedLat = 0 + savedLong = 0 + savedAlt = 0 + nvMode = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = Custom01 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527150 + partName = Part + pos = 1.82057095,7.90945816,-6.15348816 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.10202599,1.50024104,1.10202599 + rot = -1.00000012,0,0,-6.85453415E-07 + attRot = 0,0,0,-0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294527126 + srfN = srfAttach,structuralPanel2_4294527422 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527126 + partName = Part + pos = -5.63817501,7.90945244,-6.15349293 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.10202599,1.50024104,-1.10202706 + rot = 1.00000012,3.26668285E-14,-2.26093422E-14,6.85453415E-07 + attRot = 0,0,0,-0.999999881 + attRot0 = 1.02006001E-14,-1,-3.66099897E-07,-4.37113883E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294527150 + srfN = srfAttach,structuralPanel2_4294527398 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527102 + partName = Part + pos = 1.82191944,7.90897369,-0.693904638 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,-1.11265802 + rot = 1.00000012,0,0,6.85453415E-07 + attRot = 0,0,0,0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294527078 + srfN = srfAttach,structuralPanel2_4294527326 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294527078 + partName = Part + pos = -5.63952065,7.90898418,-0.693914652 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,1.11265802 + rot = 1.00000012,3.26668285E-14,-2.26093422E-14,6.85453415E-07 + attRot = 0,0,0,0.999999881 + attRot0 = 1.02006001E-14,-1,-3.66099897E-07,-4.37113883E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294527102 + srfN = srfAttach,structuralPanel2_4294527302 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4294527054 + partName = Part + pos = -1.91912293,14.4995003,-6.33236408 + attPos = 0,0,0 + attPos0 = 0.00982248783,0.672397614,-0.324572086 + rot = 0,-1.00000012,5.96046448E-07,0 + attRot = 0,0,0,-0.999999881 + attRot0 = 0,-1,2.98023195E-07,0 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4294527000 + sym = LgRadialSolarPanel_4294526946 + sym = LgRadialSolarPanel_4294526892 + srfN = srfAttach,trussPiece3x_4294527254 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4294527000 + partName = Part + pos = -2.2535162,14.4994917,-6.01761723 + attPos = 0,0,0 + attPos0 = -0.324569792,0.672397614,-0.00982451439 + rot = -2.98023224E-08,-0.707106948,3.57627869E-07,0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.107342E-07,-0.707106829,2.107342E-07,0.707106829 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4294527054 + sym = LgRadialSolarPanel_4294526946 + sym = LgRadialSolarPanel_4294526892 + srfN = srfAttach,trussPiece3x_4294527254 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4294526946 + partName = Part + pos = -1.93876791,14.499505,-5.68321133 + attPos = 0,0,0 + attPos0 = -0.00982248783,0.672397077,0.324568987 + rot = 1.1920929E-07,4.37114061E-08,-3.55271368E-14,1.00000012 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.9802311E-07,4.37113883E-08,-1.30270101E-14,1 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4294527054 + sym = LgRadialSolarPanel_4294527000 + sym = LgRadialSolarPanel_4294526892 + srfN = srfAttach,trussPiece3x_4294527254 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4294526892 + partName = Part + pos = -1.60437584,14.4994984,-5.99797153 + attPos = 0,0,0 + attPos0 = 0.324569792,0.672397614,0.00982022285 + rot = -2.98023224E-08,0.707106948,-3.57627869E-07,0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.107342E-07,0.707106829,-2.107342E-07,0.707106829 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4294527054 + sym = LgRadialSolarPanel_4294527000 + sym = LgRadialSolarPanel_4294526946 + srfN = srfAttach,trussPiece3x_4294527254 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = rtg_4294526696 + partName = Part + pos = -3.47691321,9.04123211,-5.09077454 + attPos = 0,0,0 + attPos0 = 0.568121672,-0.343470216,-0.328006238 + rot = 4.96417974E-15,0,-1.00000012,-3.12895665E-16 + attRot = 0,0,0,1 + attRot0 = 1,-7.10542524E-15,4.37113883E-08,2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = rtg_4294526664 + srfN = srfAttach,structuralPanel2_4294527670 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGenerator + isEnabled = True + generatorIsActive = False + throttle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCoreHeat + isEnabled = True + CoreTempGoalAdjustment = 0 + CoreThermalEnergy = 0 + stagingEnabled = True + lastUpdateTime = 0 + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 23300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = rtg_4294526664 + partName = Part + pos = -0.340665102,9.04123211,-5.09077454 + attPos = 0,0,0 + attPos0 = 0.568121672,-0.343470216,0.328007311 + rot = -3.55271368E-15,1.1920929E-07,-1.00000012,3.55271326E-15 + attRot = 0,0,0,1 + attRot0 = -3.5527122E-15,3.27825546E-07,-1,3.55271347E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = rtg_4294526696 + srfN = srfAttach,structuralPanel2_4294527694 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGenerator + isEnabled = True + generatorIsActive = False + throttle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCoreHeat + isEnabled = True + CoreTempGoalAdjustment = 0 + CoreThermalEnergy = 0 + stagingEnabled = True + lastUpdateTime = 0 + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 23300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = ksp.r.largeBatteryPack_4294526400 + partName = Part + pos = -3.28654933,9.3681221,-4.10155582 + attPos = 0,0,0 + attPos0 = 0.377760649,-0.0166690387,0.65430063 + rot = 0.707106829,1.25607405E-15,1.3816815E-14,-0.707106948 + attRot = 0,0,0,1 + attRot0 = -3.09086232E-08,0.707107067,0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4294526376 + srfN = srfAttach,structuralPanel2_4294527622 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = ksp.r.largeBatteryPack_4294526376 + partName = Part + pos = -0.531028271,9.36812305,-4.10156059 + attPos = 0,0,0 + attPos0 = 0.377759248,-0.0166690387,-0.654299676 + rot = -0.707106709,2.96461532E-21,1.25607481E-14,0.707107067 + attRot = 0,0,0,1 + attRot0 = -0.707106471,-4.23516423E-22,1.25607464E-14,0.707107186 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4294526400 + srfN = srfAttach,structuralPanel2_4294527646 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = ksp.r.largeBatteryPack_4294526352 + partName = Part + pos = -3.2559123,9.36812305,-3.10013223 + attPos = 0,0,0 + attPos0 = 0.347124368,-0.0166693665,-0.347122699 + rot = 0.707106829,1.25607405E-15,1.3816815E-14,-0.707106948 + attRot = 0,0,0,1 + attRot0 = -3.09086232E-08,0.707107067,0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4294526328 + srfN = srfAttach,structuralPanel2_4294527622 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = ksp.r.largeBatteryPack_4294526328 + partName = Part + pos = -0.561664343,9.36812305,-3.10013223 + attPos = 0,0,0 + attPos0 = 0.347123265,-0.0166693665,0.347123682 + rot = -0.707106709,2.96461532E-21,1.25607481E-14,0.707107067 + attRot = 0,0,0,1 + attRot0 = -0.707106471,-4.23516423E-22,1.25607464E-14,0.707107186 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4294526352 + srfN = srfAttach,structuralPanel2_4294527646 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralPanel2_4294526304 + partName = Part + pos = 2.99442434,9.41755104,-1.43568873 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.91427612,-0.0166683327,5.79530251E-07 + rot = -8.34465027E-07,0,0,1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,0,0,2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294526280 + sym = structuralPanel2_4294526202 + srfN = srfAttach,structuralPanel2_4294527326 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294526280 + partName = Part + pos = 4.98335886,9.43421936,-1.43568993 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = -1.00000012,0,0,-1.1920929E-06 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294526256 + sym = structuralPanel2_4294526178 + srfN = srfAttach,structuralPanel2_4294526304 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294526256 + partName = Part + pos = 5.7251296,7.94231272,-0.693905115 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,-1.11265802 + rot = 1.00000012,0,0,1.28149986E-06 + attRot = 0,0,0,0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294526154 + srfN = srfAttach,structuralPanel2_4294526280 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294526202 + partName = Part + pos = -6.81202364,9.41755104,-1.43568826 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.91426837,-0.0166683327,-1.72185807E-07 + rot = 3.55271368E-14,1.00000012,-8.34465027E-07,-4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,-8.28808102E-15,8.7422805E-08,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294526178 + sym = structuralPanel2_4294526304 + srfN = srfAttach,structuralPanel2_4294527302 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294526178 + partName = Part + pos = -8.80095673,9.43422127,-1.43568921 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = -4.3711502E-08,1.1920929E-06,1.00000012,-4.79616347E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294526154 + sym = structuralPanel2_4294526280 + srfN = srfAttach,structuralPanel2_4294526202 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294526154 + partName = Part + pos = -9.5427494,7.94231796,-0.693909883 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,-1.11265802 + rot = 1.00000012,-3.39240952E-15,5.02429875E-15,1.28149986E-06 + attRot = 0,0,0,0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294526256 + srfN = srfAttach,structuralPanel2_4294526178 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294526100 + partName = Part + pos = 3.0004015,9.41812897,-3.44726062 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.95009184,-0.016668329,1.1755767E-06 + rot = -8.34465027E-07,0,0,1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -1,0,0,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294632856 + sym = structuralPanel2_4294526022 + srfN = srfAttach,structuralPanel2_4294527374 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294632856 + partName = Part + pos = 4.98933649,9.43479729,-3.44726157 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = -1.00000012,0,0,-1.1920929E-06 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = largeAdapter_4294537426 + link = trussPiece3x_4291278424 + sym = structuralPanel2_4294525998 + srfN = srfAttach,structuralPanel2_4294526100 + attN = bottom,largeAdapter_4294537426 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294526022 + partName = Part + pos = -6.81800127,9.41812897,-3.44726014 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.95008361,-0.016668329,-1.47908884E-06 + rot = 3.55271368E-14,1.00000012,-8.34465027E-07,-4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,-8.28808102E-15,8.7422805E-08,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294525998 + sym = structuralPanel2_4294526100 + srfN = srfAttach,structuralPanel2_4294527350 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294525998 + partName = Part + pos = -8.80693436,9.43479729,-3.4472611 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = -4.3711502E-08,1.1920929E-06,1.00000012,-4.79616347E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = largeAdapter_4294524612 + link = trussPiece3x_4291279714 + sym = structuralPanel2_4294632856 + srfN = srfAttach,structuralPanel2_4294526022 + attN = bottom,largeAdapter_4294524612 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294525944 + partName = Part + pos = 2.92368078,9.41803932,-5.41878891 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.83779407,-0.016668329,9.37158006E-07 + rot = -8.34465027E-07,0,0,1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -1,0,0,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294525920 + link = trussPiece3x_4294482400 + sym = structuralPanel2_4294525866 + srfN = srfAttach,structuralPanel2_4294527422 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294525920 + partName = Part + pos = 4.91261625,9.43470764,-5.41878986 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = -1.00000012,0,0,-1.1920929E-06 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294525764 + sym = structuralPanel2_4294525842 + srfN = srfAttach,structuralPanel2_4294525944 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294525866 + partName = Part + pos = -6.74128008,9.41803932,-5.41878891 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.83778369,-0.016668329,-2.20280413E-06 + rot = 3.55271368E-14,1.00000012,-8.34465027E-07,-4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,-8.28808102E-15,8.7422805E-08,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4294525842 + link = trussPiece3x_4294478354 + sym = structuralPanel2_4294525944 + srfN = srfAttach,structuralPanel2_4294527398 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4294525842 + partName = Part + pos = -8.73021507,9.43470764,-5.41878986 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = -4.3711502E-08,1.1920929E-06,1.00000012,-4.79616347E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4294525788 + sym = structuralPanel2_4294525920 + srfN = srfAttach,structuralPanel2_4294525866 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294525788 + partName = Part + pos = -9.38731956,7.9427948,-6.075881 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0.657082438,1.49190676,-0.65708214 + rot = -6.29566217E-15,1.07288361E-06,1.00000012,1.50387125E-14 + attRot = 0,0,0,0.999999881 + attRot0 = -8.94069956E-08,-4.37114096E-08,1.29075658E-14,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294525764 + srfN = srfAttach,structuralPanel2_4294525842 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294525764 + partName = Part + pos = 5.5696969,7.94279528,-6.07588291 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0.657081842,1.49190676,0.657081664 + rot = -2.131626E-14,9.23871994E-07,1.00000012,2.13162567E-14 + attRot = 0,0,0,0.999999881 + attRot0 = 2.13162753E-14,-1,-1.49011527E-07,2.13162313E-14 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4294525788 + srfN = srfAttach,structuralPanel2_4294525920 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = largeAdapter_4294537426 + partName = Part + pos = 4.38933611,10.2347984,-3.44726348 + attPos = -0.600000381,-0.0175008774,9.21337687E-07 + attPos0 = 0,-0.782500863,-7.71582791E-07 + rot = 0,0,0,1.00000012 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = 1,0,0,-1.16229046E-06 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = missileTurretTest_4294617156 + attN = top,missileTurretTest_4294617156 + attN = bottom,structuralPanel2_4294632856 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 2.5 + defaultScale = 2.5 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileTurretTest_4294617156 + partName = Part + pos = 4.38933611,11.421032,-3.44726324 + attPos = 0,0,0 + attPos0 = 0,1.18622327,-3.20816298E-08 + rot = 0,0,0,1.00000012 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAGM-65_4294577354 + link = bahaAGM-65_4294573086 + link = bahaAGM-65_4294572060 + link = bahaAGM-65_4294571044 + link = bahaAGM-114_4294566604 + link = bahaAGM-114_4294562796 + link = bahaAGM-114_4294561794 + link = bahaAGM-114_4294560802 + attN = bottom,largeAdapter_4294537426 + attN = missile1,bahaAGM-114_4294566604 + attN = missile2,bahaAGM-65_4294573086 + attN = missile3,bahaAGM-114_4294562796 + attN = missile4,bahaAGM-65_4294577354 + attN = missile5,bahaAGM-114_4294560802 + attN = missile6,bahaAGM-65_4294571044 + attN = missile7,bahaAGM-114_4294561794 + attN = missile8,bahaAGM-65_4294572060 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 75 + minPitch = -8 + yawRange = 360 + minPitchLimit = -8 + maxPitchLimit = 75 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MissileTurret + isEnabled = True + autoReturn = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 80 + minPitch = -1 + yawRange = 360 + minPitchLimit = -1 + maxPitchLimit = 80 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4294577354 + partName = Part + pos = 5.67863894,12.0108557,-2.47337437 + attPos = 0,0,0 + attPos0 = 1.28930259,0.589826941,0.973881423 + rot = 0,-1.43051147E-06,1.00000012,0 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-1.43051136E-06,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4294573086 + partName = Part + pos = 5.09632826,12.0108557,-2.47337437 + attPos = 0,0,0 + attPos0 = 0.706991911,0.589826941,0.973881423 + rot = 0,-1.43051147E-06,1.00000012,0 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-1.43051136E-06,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4294572060 + partName = Part + pos = 5.67863894,11.3979349,-2.47337532 + attPos = 0,0,0 + attPos0 = 1.28930259,-0.023094818,0.973880529 + rot = 1.43051147E-06,0,0,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 1.43051136E-06,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-65_4294571044 + partName = Part + pos = 5.09632826,11.3979349,-2.47337532 + attPos = 0,0,0 + attPos0 = 0.706991911,-0.023094818,0.973880529 + rot = -1.43051147E-06,0,0,-1.00000012 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = -1.43051136E-06,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-65 + maxStaticLaunchRange = 5500 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 5500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4294566604 + partName = Part + pos = 3.68234396,11.9498587,-2.57337475 + attPos = 0,0,0 + attPos0 = -0.706992149,0.528827667,0.873881102 + rot = 0,-1.43051147E-06,1.00000012,0 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-1.43051136E-06,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-114 + maxStaticLaunchRange = 4000 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 16 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 4000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4294562796 + partName = Part + pos = 3.10003328,11.9498587,-2.57337475 + attPos = 0,0,0 + attPos0 = -1.28930283,0.528827667,0.873881102 + rot = 0,-1.43051147E-06,1.00000012,0 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-1.43051136E-06,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-114 + maxStaticLaunchRange = 4000 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 16 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 4000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4294561794 + partName = Part + pos = 3.10003328,11.4589348,-2.5733757 + attPos = 0,0,0 + attPos0 = -1.28930283,0.0379054025,0.873880565 + rot = 1.43051147E-06,0,0,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 1.43051136E-06,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-114 + maxStaticLaunchRange = 4000 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 16 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 4000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4294560802 + partName = Part + pos = 3.68234396,11.4589348,-2.5733757 + attPos = 0,0,0 + attPos0 = -0.706992149,0.0379054025,0.873880565 + rot = 1.43051147E-06,0,0,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 1.43051136E-06,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294617156 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AGM-114 + maxStaticLaunchRange = 4000 + minStaticLaunchRange = 800 + maxOffBoresight = 50 + DetonationDistance = 16 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 800 + engageRangeMax = 4000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = largeAdapter_4294524612 + partName = Part + pos = -8.10693932,10.2348013,-3.44726062 + attPos = -0.699998379,-0.0174999237,-9.24522169E-07 + attPos0 = 1.90734852E-06,-0.782500863,9.16869794E-07 + rot = 0,-1.00485924E-14,0,1.00000012 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = 4.37114238E-08,-1.16229046E-06,-1,-5.23451623E-14 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = missileTurretTest_4294525740 + attN = top,missileTurretTest_4294525740 + attN = bottom,structuralPanel2_4294525998 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 2.5 + defaultScale = 2.5 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileTurretTest_4294525740 + partName = Part + pos = -8.10693932,11.42103,-3.44725895 + attPos = 0,0,0 + attPos0 = 0,1.18622279,-6.25239807E-07 + rot = 0,-1.00485924E-14,0,1.00000012 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim9_4294525590 + link = bahaAim9_4294525534 + link = bahaAim9_4294525478 + link = bahaAim9_4294525422 + link = bahaAim120_4294525366 + link = bahaAim120_4294525326 + link = bahaAim120_4294525286 + link = bahaAim120_4294525246 + attN = bottom,largeAdapter_4294524612 + attN = missile1,bahaAim120_4294525366 + attN = missile2,bahaAim9_4294525534 + attN = missile3,bahaAim120_4294525326 + attN = missile4,bahaAim9_4294525590 + attN = missile5,bahaAim120_4294525286 + attN = missile6,bahaAim9_4294525422 + attN = missile7,bahaAim120_4294525246 + attN = missile8,bahaAim9_4294525478 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 75 + minPitch = -8 + yawRange = 360 + minPitchLimit = -8 + maxPitchLimit = 75 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MissileTurret + isEnabled = True + autoReturn = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 80 + minPitch = -1 + yawRange = 360 + minPitchLimit = -1 + maxPitchLimit = 80 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4294525590 + partName = Part + pos = -6.81763411,11.9227381,-2.57337213 + attPos = 0,0,0 + attPos0 = 1.2893033,0.501708627,0.873880804 + rot = -3.42353607E-14,-6.85453415E-07,1.00000012,-5.76966656E-15 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-8.34464913E-07,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-9 + maxStaticLaunchRange = 4200 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 15 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 200 + engageRangeMax = 4200 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4294525534 + partName = Part + pos = -7.39994478,11.9227371,-2.57337284 + attPos = 0,0,0 + attPos0 = 0.706991911,0.501708627,0.873880804 + rot = -3.42353607E-14,-6.85453415E-07,1.00000012,-5.76966656E-15 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-8.34464913E-07,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-9 + maxStaticLaunchRange = 4200 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 15 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 200 + engageRangeMax = 4200 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4294525478 + partName = Part + pos = -6.81763411,11.4860525,-2.57337451 + attPos = 0,0,0 + attPos0 = 1.2893033,0.0650239736,0.873880327 + rot = 6.85453415E-07,-4.52186642E-14,5.02429621E-15,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 8.34464913E-07,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-9 + maxStaticLaunchRange = 4200 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 15 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 200 + engageRangeMax = 4200 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4294525422 + partName = Part + pos = -7.39994478,11.4860525,-2.57337189 + attPos = 0,0,0 + attPos0 = 0.706991911,0.0650239736,0.873880327 + rot = 6.85453415E-07,-4.52186642E-14,5.02429621E-15,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 8.34464913E-07,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 0 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-9 + maxStaticLaunchRange = 4200 + minStaticLaunchRange = 200 + maxOffBoresight = 50 + DetonationDistance = 15 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 200 + engageRangeMax = 4200 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4294525366 + partName = Part + pos = -8.81393051,11.9508581,-2.39837098 + attPos = 0,0,0 + attPos0 = -0.706992149,0.529827535,1.04888082 + rot = -3.42353607E-14,-6.85453415E-07,1.00000012,-5.76966656E-15 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-8.34464913E-07,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-120 + maxStaticLaunchRange = 7500 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 500 + engageRangeMax = 7500 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4294525326 + partName = Part + pos = -9.3962574,11.9508581,-2.39837098 + attPos = 0,0,0 + attPos0 = -1.28930306,0.529827535,1.04888082 + rot = -3.42353607E-14,-6.85453415E-07,1.00000012,-5.76966656E-15 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 0,-8.34464913E-07,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-120 + maxStaticLaunchRange = 7500 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 500 + engageRangeMax = 7500 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4294525286 + partName = Part + pos = -8.81393051,11.4579344,-2.39837337 + attPos = 0,0,0 + attPos0 = -0.706992149,0.0369047225,1.04888058 + rot = 6.85453415E-07,-4.52186642E-14,5.02429621E-15,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 8.34464913E-07,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-120 + maxStaticLaunchRange = 7500 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 500 + engageRangeMax = 7500 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4294525246 + partName = Part + pos = -9.3962574,11.4579344,-2.39837337 + attPos = 0,0,0 + attPos0 = -1.28930306,0.0369047225,1.04888058 + rot = 6.85453415E-07,-4.52186642E-14,5.02429621E-15,1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 8.34464913E-07,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294525740 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = AIM-120 + maxStaticLaunchRange = 7500 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 20 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 500 + engageRangeMax = 7500 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = largeAdapter_4294515742 + partName = Part + pos = -1.90878272,10.1842165,-1.63568711 + attPos = -1.00000048,0.0174999833,0.200000197 + attPos0 = -8.32644399E-15,0.782500565,0 + rot = 0,-1.00485924E-14,0,1.00000012 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = -1.06581402E-14,-1,2.38418551E-07,-4.37113883E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = missileTurretTest_4294515704 + attN = top,missileTurretTest_4294515704 + attN = bottom,structuralPanel2_4294527574 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 2.5 + defaultScale = 2.5 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileTurretTest_4294515704 + partName = Part + pos = -1.90878463,11.3704472,-1.63568425 + attPos = 0,0,0 + attPos0 = -1.90734909E-06,1.18622386,-6.84844963E-07 + rot = 0,-1.00485924E-14,0,1.00000012 + attRot = 0.707106709,0,0,-0.707106709 + attRot0 = 1.00974184E-28,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaPac-3_4294502232 + link = bahaPac-3_4294499620 + link = bahaPac-3_4294498646 + link = bahaPac-3_4294497672 + link = bahaHarm_4294476036 + link = bahaHarm_4294470466 + attN = bottom,largeAdapter_4294515742 + attN = missile2,bahaPac-3_4294497672 + attN = missile3,bahaHarm_4294476036 + attN = missile6,bahaPac-3_4294498646 + attN = missile7,bahaHarm_4294470466 + attN = missile8,bahaPac-3_4294499620 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 75 + minPitch = -8 + yawRange = 360 + minPitchLimit = -8 + maxPitchLimit = 75 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = MissileTurret + isEnabled = True + autoReturn = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 80 + minPitch = -1 + yawRange = 360 + minPitchLimit = -1 + maxPitchLimit = 80 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaPac-3_4294502232 + partName = Part + pos = -0.619477034,11.9445925,-0.761799216 + attPos = 0,0,0 + attPos0 = 1.28930402,0.574144244,0.873881459 + rot = 1.32976075E-14,0,-1.00000012,2.14994546E-14 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 2.54109844E-21,-1.00974184E-28,-1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294515704 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = PAC-3 Intercept Missile + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 2000 + maxOffBoresight = 50 + DetonationDistance = 35 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 2000 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaPac-3_4294499620 + partName = Part + pos = -0.619477034,11.3630381,-0.761799216 + attPos = 0,0,0 + attPos0 = 1.28930402,-0.00741112232,0.873881459 + rot = 0,1.00485924E-14,0,-1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 1.51461282E-28,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294515704 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = PAC-3 Intercept Missile + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 2000 + maxOffBoresight = 50 + DetonationDistance = 35 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 2000 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaPac-3_4294498646 + partName = Part + pos = -1.20178771,11.3630362,-0.761799097 + attPos = 0,0,0 + attPos0 = 0.706993163,-0.00741112232,0.8738814 + rot = 0,1.00485924E-14,0,-1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 1.51461282E-28,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294515704 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = PAC-3 Intercept Missile + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 2000 + maxOffBoresight = 50 + DetonationDistance = 35 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 2000 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaPac-3_4294497672 + partName = Part + pos = -1.20178771,11.9445925,-0.761799216 + attPos = 0,0,0 + attPos0 = 0.706993163,0.574144244,0.873881519 + rot = -1.32976075E-14,0,1.00000012,-2.14994546E-14 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = -2.54109844E-21,1.00974184E-28,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294515704 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = PAC-3 Intercept Missile + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 2000 + maxOffBoresight = 50 + DetonationDistance = 35 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 2000 + engageRangeMax = 15000 + engageAir = True + engageMissile = False + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294486074 + partName = Part + pos = 0.68588686,10.401371,-6.61880016 + attPos = -0.0248396397,0.146764636,0.0351362228 + attPos0 = -0.375160456,-1.14676571,1.16486621 + rot = -0.342020929,0,0,0.939692557 + attRot = 0.342020124,0,0,-0.939692557 + attRot0 = -0.939692557,0,0,-0.342020452 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaRBS-15Cruise_4294487832 + sym = trussPiece3x_4294479658 + srfN = srfAttach,structuralPanel2_4294527422 + attN = top,bahaRBS-15Cruise_4294487832 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaRBS-15Cruise_4294487832 + partName = Part + pos = 0.68588686,11.7151489,-7.72119427 + attPos = 0,0,0 + attPos0 = 0,1.71500969,-1.94222821E-06 + rot = 0,0.342020929,0.939692557,0 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaRBS-15Cruise_4294479618 + attN = top,trussPiece3x_4294486074 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 1 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = RBS-15 Cruise Missile + maxStaticLaunchRange = 40000 + minStaticLaunchRange = 700 + maxOffBoresight = 360 + DetonationDistance = 30 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 700 + engageRangeMax = 40000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294479658 + partName = Part + pos = -4.50347233,10.401371,-6.61880207 + attPos = -0.0248394012,0.146764636,-0.0351382494 + attPos0 = -0.375174493,-1.14676571,-1.16486788 + rot = 0.342021078,1.88411129E-14,4.39625922E-14,-0.939692378 + attRot = 0.342020124,0,0,-0.939692557 + attRot0 = -4.10753067E-08,-0.342020363,0.939692616,-1.49501851E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaRBS-15Cruise_4294479618 + sym = trussPiece3x_4294486074 + srfN = srfAttach,structuralPanel2_4294527398 + attN = top,bahaRBS-15Cruise_4294479618 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaRBS-15Cruise_4294479618 + partName = Part + pos = -4.50347233,11.7151432,-7.72119045 + attPos = 0,0,0 + attPos0 = 0,1.71500969,-1.94222821E-06 + rot = 7.53644431E-15,-0.342021078,-0.939692378,3.76822173E-15 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaRBS-15Cruise_4294487832 + attN = top,trussPiece3x_4294479658 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 1 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = RBS-15 Cruise Missile + maxStaticLaunchRange = 40000 + minStaticLaunchRange = 700 + maxOffBoresight = 360 + DetonationDistance = 30 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 700 + engageRangeMax = 40000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294482400 + partName = Part + pos = 2.02368069,10.3180408,-6.61880112 + attPos = -0.046236515,-0.246763706,-0.0229697227 + attPos0 = -0.85376358,1.14676607,-1.17703223 + rot = -0.342021435,0,0,0.939692259 + attRot = 0.342020124,0,0,-0.939692557 + attRot0 = -0.342020422,0,0,0.939692497 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaRBS-15Cruise_4294482360 + sym = trussPiece3x_4294478354 + srfN = srfAttach,structuralPanel2_4294525944 + attN = top,bahaRBS-15Cruise_4294482360 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaRBS-15Cruise_4294482360 + partName = Part + pos = 2.02368069,11.6318169,-7.72119617 + attPos = 0,0,0 + attPos0 = 0,1.71500969,-1.94222821E-06 + rot = 0,0.342021435,0.939692259,0 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaRBS-15Cruise_4294478308 + attN = top,trussPiece3x_4294482400 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 1 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = RBS-15 Cruise Missile + maxStaticLaunchRange = 40000 + minStaticLaunchRange = 700 + maxOffBoresight = 360 + DetonationDistance = 30 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 700 + engageRangeMax = 40000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4294478354 + partName = Part + pos = -5.84126568,10.3180408,-6.61880302 + attPos = -0.0462369919,-0.246763706,0.0229715109 + attPos0 = -0.85376966,1.14676607,1.17703271 + rot = 0.342021435,1.63289622E-14,2.63775547E-14,-0.939692259 + attRot = 0.342020124,0,0,-0.939692557 + attRot0 = -1.49501869E-08,0.939692497,0.342020422,4.10752676E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaRBS-15Cruise_4294478308 + sym = trussPiece3x_4294482400 + srfN = srfAttach,structuralPanel2_4294525866 + attN = top,bahaRBS-15Cruise_4294478308 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaRBS-15Cruise_4294478308 + partName = Part + pos = -5.84126568,11.6318102,-7.72119141 + attPos = 0,0,0 + attPos0 = 0,1.71500969,-1.94222821E-06 + rot = -6.28036983E-14,-0.342021435,-0.939692259,1.25607193E-15 + attRot = 0,-0.707106709,-0.707106709,0 + attRot0 = 0,0,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaRBS-15Cruise_4294482360 + attN = top,trussPiece3x_4294478354 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 1 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = RBS-15 Cruise Missile + maxStaticLaunchRange = 40000 + minStaticLaunchRange = 700 + maxOffBoresight = 360 + DetonationDistance = 30 + dropTime = 0 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 700 + engageRangeMax = 40000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaHarm_4294476036 + partName = Part + pos = -3.19809151,11.9364891,-0.361796856 + attPos = 0,0,0 + attPos0 = -1.28930295,0.566038251,1.27388179 + rot = 1.32976075E-14,0,-1.00000012,2.14994546E-14 + attRot = 0,0.707106709,0.707106709,0 + attRot0 = 2.54109844E-21,-1.00974184E-28,-1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294515704 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = HARM + maxStaticLaunchRange = 10000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 15 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 500 + engageRangeMax = 10000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaHarm_4294470466 + partName = Part + pos = -3.19809151,11.3711452,-0.361797571 + attPos = 0,0,0 + attPos0 = -1.28930295,0.000695466995,1.27388203 + rot = 0,1.00485924E-14,0,-1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = 1.51461282E-28,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,missileTurretTest_4294515704 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 5 + cruiseAltitude = 500 + maxAltitude = 0 + shortName = HARM + maxStaticLaunchRange = 10000 + minStaticLaunchRange = 500 + maxOffBoresight = 50 + DetonationDistance = 15 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + engageRangeMin = 500 + engageRangeMax = 10000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291279714 + partName = Part + pos = -9.48241425,7.94288826,-3.4268117 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0.67547369,1.49190831,0.0204465389 + rot = 1.00000012,-1.3542147E-12,-1.34399891E-12,1.07288361E-06 + attRot = 0,0,0,0.999999881 + attRot0 = -1.35559576E-12,-1,1.19209233E-07,-4.37128307E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4291278424 + srfN = srfAttach,structuralPanel2_4294525998 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291278424 + partName = Part + pos = 5.66482306,7.94288826,-3.4268117 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0.675486326,1.49190831,-0.0204463955 + rot = 1.00000012,1.35003272E-12,1.35003272E-12,1.07288361E-06 + attRot = 0,0,0,0.999999881 + attRot0 = -1.19209233E-07,-1.35003413E-12,1.35003109E-12,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4291279714 + srfN = srfAttach,structuralPanel2_4294632856 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileController_4294526838 + partName = Part + pos = -0.302263737,9.3653698,-5.76896095 + attPos = 0,0,0 + attPos0 = 0.606523752,-0.0193332173,-0.350178361 + rot = -2.32831671E-10,-1.00000012,4.76837158E-07,2.32831671E-10 + attRot = 0,-0.99999994,0,0 + attRot0 = -2.32831587E-10,-1,2.38418551E-07,2.32831698E-10 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4294527694 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileFire + isEnabled = True + weaponIndex = 0 + targetScanInterval = 3 + fireBurstLength = 0 + guardAngle = 360 + guardRange = 5000 + gunRange = 2000 + maxMissilesOnTarget = 1 + guardMode = False + team = False + isArmed = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggleGuardMode + { + actionGroup = Custom09 + } + AGToggleTargetType + { + actionGroup = None + } + AGJettisonWeapon + { + actionGroup = None + } + AGToggleTeam + { + actionGroup = None + } + AGToggleArm + { + actionGroup = None + } + AGFire + { + actionGroup = Custom06 + } + AGFireGunsHold + { + actionGroup = None + } + AGFireGunsToggle + { + actionGroup = None + } + AGCycle + { + actionGroup = Custom07 + } + AGCycleBack + { + actionGroup = Custom08 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = RadarWarningReceiver + isEnabled = True + rwrEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWingCommander + isEnabled = True + savedWingmen = + commandSelf = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Platform.craft b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Platform.craft new file mode 100644 index 000000000..c5b59154e --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/craft/BDA - Test Platform.craft @@ -0,0 +1,6063 @@ +ship = BDA - Test Platform +version = 1.3.0 +description = +type = SPH +size = 16.1028137,9.33359528,13.5166655 +PART +{ + part = sasModule_4284270764 + partName = Part + pos = -3.57586646,8.04845428,-0.272817641 + attPos = 0,0,0 + attPos0 = 1.56324098E-14,-1.56634903,1.78813906E-07 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = -1,0,4.37113883E-08,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143996 + attN = bottom,trussPiece3x_4291143996 + attN = top,probeCoreOcto2_4284205004 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleReactionWheel + isEnabled = True + actuatorModeCycle = 1 + authorityLimiter = 100 + stateString = Active + stagingEnabled = True + WheelState = Active + EVENTS + { + } + ACTIONS + { + CycleAction + { + actionGroup = None + } + Activate + { + actionGroup = None + } + Deactivate + { + actionGroup = None + } + Toggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 0.625 + defaultScale = 0.625 + defaultTransformScale = (0.5, 0.5, 0.5) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = probeCoreOcto2_4284205004 + partName = Part + pos = -3.57586646,8.04845428,-0.120643631 + attPos = 0,0,0 + attPos0 = -3.57586646,8.04845428,-0.120643631 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 0.707106769,0,0,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = sasModule_4284270764 + attN = bottom,sasModule_4284270764 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleCommand + isEnabled = True + hibernation = False + hibernateOnWarp = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + HibernateToggle + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSAS + isEnabled = True + standaloneToggle = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleKerbNetAccess + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OpenKerbNetAction + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 1479.99988 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTCA + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + onActionUpdate + { + actionGroup = None + active = False + } + ToggleTCA + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTripLogger + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + Log + { + flight = 0 + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 5 + maxAmount = 5 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = trussPiece3x_4291143996 + partName = Part + pos = -3.57586646,8.04845333,-1.83917511 + attPos = -1.57232896E-14,-0.0202863198,0.238357604 + attPos0 = 0,-1.56634903,1.86723398E-07 + rot = -0.707106829,0,0,0.707106829 + attRot = 0.999999881,0,0,0 + attRot0 = 1,0,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143972 + link = structuralPanel2_4291143828 + link = structuralPanel2_4291143804 + attN = bottom,sasModule_4284270764 + attN = top,trussPiece3x_4291143972 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143972 + partName = Part + pos = -3.57586646,8.04845238,-3.93917656 + attPos = 0,-0.850475311,1.28207176E-07 + attPos0 = 0,2.95047593,-3.51724196E-07 + rot = -0.707106829,0,0,0.707106829 + attRot = 0.999999881,0,0,0 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143948 + link = structuralPanel2_4291411116 + link = structuralPanel2_4291411092 + attN = bottom,trussPiece3x_4291143996 + attN = top,trussPiece3x_4291143948 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143948 + partName = Part + pos = -3.57586646,8.04845238,-5.93917847 + attPos = 0,-0.950474501,-1.25112621E-07 + attPos0 = 0,2.95047688,-3.51724196E-07 + rot = -0.707106829,0,0,0.707106829 + attRot = 0.999999881,0,0,0 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4291143924 + link = structuralPanel2_4291143900 + link = trussPiece3x_4291143732 + attN = bottom,trussPiece3x_4291143972 + attN = top,trussPiece3x_4291143732 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143924 + partName = Part + pos = -2.57586575,8.37392616,-5.82176113 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1,-0.117423102,0.325475812 + rot = 2.38418579E-07,0,0,-1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -0.70710659,0,0,-0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4291143602 + link = trussPiece3x_4291143458 + link = rtg_4291142590 + link = bahaCannonShellBox_4291142374 + link = missileController_4291142920 + sym = structuralPanel2_4291143900 + srfN = srfAttach,trussPiece3x_4291143948 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143900 + partName = Part + pos = -4.57586765,8.37392616,-5.82176018 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = -1,-0.117423996,0.325475812 + rot = -1.0658141E-14,-1.00000012,2.38418579E-07,4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 3.0908609E-08,-0.707107008,-0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4291143578 + link = rtg_4291142622 + link = bahaCannonShellBox_4291142406 + sym = structuralPanel2_4291143924 + srfN = srfAttach,trussPiece3x_4291143948 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291411116 + partName = Part + pos = -2.57586575,8.37401581,-3.85023546 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.5,-0.0889410973,0.32556349 + rot = 2.38418579E-07,0,0,-1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -0.70710659,0,0,-0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4291358240 + link = baha30mmAmmo_4291147338 + link = baha50CalAmmo_4291141500 + link = ksp.r.largeBatteryPack_4291140924 + link = ksp.r.largeBatteryPack_4291140766 + sym = structuralPanel2_4291411092 + srfN = srfAttach,trussPiece3x_4291143972 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291411092 + partName = Part + pos = -4.57586575,8.37401581,-3.85023451 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = -1.5,-0.0889415666,0.32556349 + rot = -1.0658141E-14,-1.00000012,2.38418579E-07,4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 3.0908609E-08,-0.707107008,-0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4291357748 + link = baha30mmAmmo_4291149408 + link = baha50CalAmmo_4291142462 + link = ksp.r.largeBatteryPack_4291149656 + link = ksp.r.largeBatteryPack_4291142510 + link = bahaOMillennium_4293573334 + sym = structuralPanel2_4291411116 + srfN = srfAttach,trussPiece3x_4291143972 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143828 + partName = Part + pos = -2.57586575,8.37343884,-1.83866954 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.5,-0.000504255295,0.324986488 + rot = 2.38418579E-07,0,0,-1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -0.70710659,0,0,-0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4291143506 + link = baha20mmAmmo_4291141366 + link = bahaH70Turret_4293555874 + sym = structuralPanel2_4291143804 + srfN = srfAttach,trussPiece3x_4291143996 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143804 + partName = Part + pos = -4.57586575,8.37343884,-1.83866954 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = -1.5,-0.000504493713,0.324986488 + rot = -1.0658141E-14,-1.00000012,2.38418579E-07,4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 3.0908609E-08,-0.707107008,-0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4291143482 + link = baha20mmAmmo_4291142342 + sym = structuralPanel2_4291143828 + srfN = srfAttach,trussPiece3x_4291143996 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143732 + partName = Part + pos = -3.57586646,8.04844761,-8.88965702 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0,2.95047593,-8.28561383E-07 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 1,0,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = scanLockRadar1_4291143708 + srfN = srfAttach,structuralPanel2_4291143924 + attN = top,trussPiece3x_4291143948 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = scanLockRadar1_4291143708 + partName = Part + pos = -3.57586646,8.37413502,-9.42842388 + attPos = 0,0,0 + attPos0 = 0,-0.538788795,-0.325687408 + rot = 0,1.00000012,-2.08616257E-07,0 + attRot = 0,0,0,-0.999999881 + attRot0 = 0,0.707106709,-0.707106888,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,trussPiece3x_4291143732 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 85 + minPitch = -8 + yawRange = 360 + minPitchLimit = -8 + maxPitchLimit = 85 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143602 + partName = Part + pos = -0.581191301,8.39059448,-5.82176685 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.99201012,0.0250024796,-1.89840705E-06 + rot = -1.00000012,0,0,-5.96046448E-07 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = 1,0,0,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143328 + link = structuralPanel2_4290932024 + sym = structuralPanel2_4291143578 + srfN = srfAttach,structuralPanel2_4291143924 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143578 + partName = Part + pos = -6.57055473,8.39059448,-5.82176495 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.99201012,0.0250024796,2.1540161E-06 + rot = 4.37114238E-08,-5.96046448E-07,-1.00000012,3.37507799E-14 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = -1,2.36533898E-16,-8.74227766E-08,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143304 + link = bahaSmokeCmPod_4291142722 + link = bahaCmPod_4291142682 + link = bahaChaffPod_4291142654 + link = structuralPanel2_4290930580 + sym = structuralPanel2_4291143602 + srfN = srfAttach,structuralPanel2_4291143900 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291358240 + partName = Part + pos = -0.616768122,8.39068413,-3.85023737 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.93864489,0.0250024796,-9.4473279E-07 + rot = -1.00000012,0,0,-5.96046448E-07 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = 1,0,0,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290933368 + link = bahaABL_4293539156 + sym = structuralPanel2_4291357748 + srfN = srfAttach,structuralPanel2_4291411116 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291357748 + partName = Part + pos = -6.53497601,8.39068413,-3.85023642 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.93864608,0.0250024796,1.19567596E-06 + rot = 4.37114238E-08,-5.96046448E-07,-1.00000012,3.37507799E-14 + attRot = 0.499999911,-0.499999911,-0.499999911,-0.499999911 + attRot0 = -1,2.36533898E-16,-8.74227766E-08,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290932338 + sym = structuralPanel2_4291358240 + srfN = srfAttach,structuralPanel2_4291411092 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143506 + partName = Part + pos = -0.58692956,8.39010715,-1.83867073 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = 1.00000012,0,0,5.96046448E-07 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143280 + link = structuralPanel2_4290935030 + link = bahaM230ChainGun_4293590744 + link = bahaHiddenVulcan_4293534536 + sym = structuralPanel2_4291143482 + srfN = srfAttach,structuralPanel2_4291143828 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4291143482 + partName = Part + pos = -6.56481361,8.39010715,-1.83867049 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,2.45914691E-07 + rot = 4.37114238E-08,-5.96046448E-07,-1.00000012,3.37507799E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,2.36533898E-16,-8.74227766E-08,2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143256 + link = structuralPanel2_4290933658 + sym = structuralPanel2_4291143506 + srfN = srfAttach,structuralPanel2_4291143804 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143458 + partName = Part + pos = -3.59602427,9.86584091,-6.41075611 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = -1.53023696,1.50023997,-0.883486271 + rot = -5.96046448E-07,0,0,1.00000012 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.67343609E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4291143434 + srfN = srfAttach,structuralPanel2_4291143924 + attN = top,trussPiece3x_4291143434 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143434 + partName = Part + pos = -3.59602427,12.8163052,-6.41076183 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0,2.95047808,-3.2976601E-07 + rot = 2.38418579E-07,0,0,-1.00000012 + attRot = -0.707106709,0,0,0.707106709 + attRot0 = -4.76837101E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaFlirBall_4291143410 + link = LgRadialSolarPanel_4291143136 + link = LgRadialSolarPanel_4291143082 + link = LgRadialSolarPanel_4291143028 + link = LgRadialSolarPanel_4291142974 + srfN = srfAttach,structuralPanel2_4291143924 + attN = bottom,trussPiece3x_4291143458 + attN = top,bahaFlirBall_4291143410 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaFlirBall_4291143410 + partName = Part + pos = -3.59602427,14.3696823,-6.41076231 + attPos = 0,0,0 + attPos0 = 0,1.55337095,-1.00847001E-06 + rot = -0.707106829,0,0,0.707106948 + attRot = 0.999999881,0,0,0 + attRot0 = 0.707106829,0,0,-0.707106888 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,trussPiece3x_4291143434 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTargetingCamera + isEnabled = True + cameraEnabled = False + currentFovIndex = 0 + slaveTurrets = False + CoMLock = False + groundStabilized = False + savedLat = 0 + savedLong = 0 + savedAlt = 0 + nvMode = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = Custom01 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143328 + partName = Part + pos = 0.153492689,6.89868641,-6.55645275 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.10202599,1.50024104,1.10202599 + rot = 1.00000012,0,0,6.85453415E-07 + attRot = 0,0,0,-0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4291143304 + srfN = srfAttach,structuralPanel2_4291143602 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143304 + partName = Part + pos = -7.30524349,6.89868116,-6.55645609 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.10202599,1.50024104,-1.10202706 + rot = -1.00000012,-7.53941401E-15,2.26093355E-14,-6.85453415E-07 + attRot = 0,0,0,-0.999999881 + attRot0 = 1.02006001E-14,-1,-3.66099897E-07,-4.37113883E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4291143328 + srfN = srfAttach,structuralPanel2_4291143578 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143280 + partName = Part + pos = 0.154841185,6.89820099,-1.09689236 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,-1.11265802 + rot = -1.00000012,0,0,-6.85453415E-07 + attRot = 0,0,0,0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4291143256 + srfN = srfAttach,structuralPanel2_4291143506 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291143256 + partName = Part + pos = -7.30658913,6.89820671,-1.0968976 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,1.11265802 + rot = -1.00000012,-7.53941401E-15,2.26093355E-14,-6.85453415E-07 + attRot = 0,0,0,0.999999881 + attRot0 = 1.02006001E-14,-1,-3.66099897E-07,-4.37113883E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4291143280 + srfN = srfAttach,structuralPanel2_4291143482 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4291143136 + partName = Part + pos = -3.58620119,13.4887066,-6.73533344 + attPos = 0,0,0 + attPos0 = 0.00982248783,0.672397614,-0.324572086 + rot = 0,1.00000012,-5.96046448E-07,0 + attRot = 0,0,0,-0.999999881 + attRot0 = 0,-1,2.98023195E-07,0 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4291143082 + sym = LgRadialSolarPanel_4291143028 + sym = LgRadialSolarPanel_4291142974 + srfN = srfAttach,trussPiece3x_4291143434 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4291143082 + partName = Part + pos = -3.92059445,13.4887028,-6.42058659 + attPos = 0,0,0 + attPos0 = -0.324569792,0.672397614,-0.00982451439 + rot = 2.98023224E-08,0.707106948,-3.57627869E-07,-0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.107342E-07,-0.707106829,2.107342E-07,0.707106829 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4291143136 + sym = LgRadialSolarPanel_4291143028 + sym = LgRadialSolarPanel_4291142974 + srfN = srfAttach,trussPiece3x_4291143434 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4291143028 + partName = Part + pos = -3.60584617,13.4887066,-6.08618879 + attPos = 0,0,0 + attPos0 = -0.00982248783,0.672397077,0.324568987 + rot = -1.1920929E-07,-4.37114061E-08,3.55271368E-14,-1.00000012 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.9802311E-07,4.37113883E-08,-1.30270101E-14,1 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4291143136 + sym = LgRadialSolarPanel_4291143082 + sym = LgRadialSolarPanel_4291142974 + srfN = srfAttach,trussPiece3x_4291143434 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = LgRadialSolarPanel_4291142974 + partName = Part + pos = -3.2714541,13.4887047,-6.40093994 + attPos = 0,0,0 + attPos0 = 0.324569792,0.672397614,0.00982022285 + rot = 2.98023224E-08,-0.707106948,3.57627869E-07,-0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 2.107342E-07,0.707106829,-2.107342E-07,0.707106829 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = LgRadialSolarPanel_4291143136 + sym = LgRadialSolarPanel_4291143082 + sym = LgRadialSolarPanel_4291143028 + srfN = srfAttach,trussPiece3x_4291143434 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDeployableSolarPanel + isEnabled = True + efficiencyMult = 1 + launchUT = -1 + currentRotation = (0, 0, 0, 1) + storedAnimationTime = 0 + storedAnimationSpeed = 0 + deployState = EXTENDED + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ExtendPanelsAction + { + actionGroup = None + active = False + } + ExtendAction + { + actionGroup = None + active = False + } + RetractAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaSmokeCmPod_4291142722 + partName = Part + pos = -7.21346569,8.45726109,-6.30869913 + attPos = 0,0,0 + attPos0 = 0.964362025,-0.0750024617,-0.730398238 + rot = -5.96046448E-07,-2.763363E-14,3.26579245E-14,1.00000012 + attRot = 0,0,0,1 + attRot0 = -4.37113883E-08,-4.65882318E-22,1,-1.0776995E-14 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291143578 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMSmoke + amount = 10 + maxAmount = 10 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4291142682 + partName = Part + pos = -6.59115982,8.51726055,-6.46837378 + attPos = 0,0,0 + attPos0 = 0.0309044775,-0.135002226,-0.969907939 + rot = -5.96046448E-07,-2.763363E-14,3.26579245E-14,1.00000012 + attRot = 0,0,0,1 + attRot0 = -4.37113883E-08,-4.65882318E-22,1,-1.0776995E-14 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291143578 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4291142654 + partName = Part + pos = -6.61895609,8.51726055,-6.12704325 + attPos = 0,0,0 + attPos0 = 0.0725990534,-0.135001659,-0.457912147 + rot = -5.96046448E-07,-2.763363E-14,3.26579245E-14,1.00000012 + attRot = 0,0,0,1 + attRot0 = -4.37113883E-08,-4.65882318E-22,1,-1.0776995E-14 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291143578 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = rtg_4291142622 + partName = Part + pos = -5.14399052,8.03045559,-5.49375343 + attPos = 0,0,0 + attPos0 = 0.568121672,-0.343470216,-0.328006238 + rot = -5.11641866E-15,0,1.00000012,4.6513459E-16 + attRot = 0,0,0,1 + attRot0 = 1,-7.10542524E-15,4.37113883E-08,2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = rtg_4291142590 + srfN = srfAttach,structuralPanel2_4291143900 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGenerator + isEnabled = True + generatorIsActive = False + throttle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCoreHeat + isEnabled = True + CoreTempGoalAdjustment = 0 + CoreThermalEnergy = 0 + stagingEnabled = True + lastUpdateTime = 0 + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 23300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = rtg_4291142590 + partName = Part + pos = -2.00774336,8.03045559,-5.49375343 + attPos = 0,0,0 + attPos0 = 0.568121672,-0.343470216,0.328007311 + rot = 3.55271368E-15,-1.1920929E-07,1.00000012,-3.55271326E-15 + attRot = 0,0,0,1 + attRot0 = -3.5527122E-15,3.27825546E-07,-1,3.55271347E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = rtg_4291142622 + srfN = srfAttach,structuralPanel2_4291143924 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGenerator + isEnabled = True + generatorIsActive = False + throttle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + } + ActivateAction + { + actionGroup = None + active = False + } + ShutdownAction + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCoreHeat + isEnabled = True + CoreTempGoalAdjustment = 0 + CoreThermalEnergy = 0 + stagingEnabled = True + lastUpdateTime = 0 + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 23300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaCannonShellBox_4291142406 + partName = Part + pos = -4.35461378,8.13145828,-5.82175922 + attPos = 0,0,0 + attPos0 = -0.221253514,-0.242467403,-3.42726793E-07 + rot = -5.11641866E-15,0,1.00000012,4.6513459E-16 + attRot = 0,0,0,1 + attRot0 = 1,-7.10542524E-15,4.37113883E-08,2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCannonShellBox_4291142374 + srfN = srfAttach,structuralPanel2_4291143900 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CannonShells + amount = 10 + maxAmount = 10 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCannonShellBox_4291142374 + partName = Part + pos = -2.79711914,8.13145828,-5.82175922 + attPos = 0,0,0 + attPos0 = -0.221253514,-0.242467403,1.34110485E-06 + rot = 3.55271368E-15,-1.1920929E-07,1.00000012,-3.55271326E-15 + attRot = 0,0,0,1 + attRot0 = -3.5527122E-15,3.27825546E-07,-1,3.55271347E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCannonShellBox_4291142406 + srfN = srfAttach,structuralPanel2_4291143924 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CannonShells + amount = 10 + maxAmount = 10 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = baha30mmAmmo_4291149408 + partName = Part + pos = -4.21401119,8.22186852,-4.47698307 + attPos = 0,0,0 + attPos0 = -0.361854225,-0.152147025,0.626749218 + rot = -5.11641866E-15,0,1.00000012,4.6513459E-16 + attRot = 0,0,0,1 + attRot0 = 1,-7.10542524E-15,4.37113883E-08,2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha30mmAmmo_4291147338 + srfN = srfAttach,structuralPanel2_4291411092 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 30x173Ammo + amount = 600 + maxAmount = 600 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = baha30mmAmmo_4291147338 + partName = Part + pos = -2.93772149,8.22186852,-4.47698307 + attPos = 0,0,0 + attPos0 = -0.361856103,-0.152147025,-0.626748264 + rot = 3.55271368E-15,-1.1920929E-07,1.00000012,-3.55271326E-15 + attRot = 0,0,0,1 + attRot0 = -3.5527122E-15,3.27825546E-07,-1,3.55271347E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha30mmAmmo_4291149408 + srfN = srfAttach,structuralPanel2_4291411116 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 30x173Ammo + amount = 600 + maxAmount = 600 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = baha50CalAmmo_4291142462 + partName = Part + pos = -4.2234025,8.24444675,-3.49777222 + attPos = 0,0,0 + attPos0 = -0.352463275,-0.129569143,-0.352462083 + rot = -1.65350945E-14,-1.1920929E-07,1.00000012,5.74332003E-15 + attRot = 0,0,0,1 + attRot0 = 1,-5.32906586E-15,4.37113989E-08,3.27825518E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha50CalAmmo_4291141500 + srfN = srfAttach,structuralPanel2_4291411092 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 50CalAmmo + amount = 1200 + maxAmount = 1200 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = baha50CalAmmo_4291141500 + partName = Part + pos = -2.92833042,8.24444675,-3.49777222 + attPos = 0,0,0 + attPos0 = -0.352464616,-0.129569143,0.352463037 + rot = 8.88178759E-15,0,1.00000012,-8.88178928E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha50CalAmmo_4291142462 + srfN = srfAttach,structuralPanel2_4291411116 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 50CalAmmo + amount = 1200 + maxAmount = 1200 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = baha20mmAmmo_4291142342 + partName = Part + pos = -4.18111038,8.24386978,-2.52240658 + attPos = 0,0,0 + attPos0 = -0.394754976,-0.129568338,0.683736801 + rot = -1.65350945E-14,-1.1920929E-07,1.00000012,5.74332003E-15 + attRot = 0,0,0,1 + attRot0 = 1,-5.32906586E-15,4.37113989E-08,3.27825518E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4291141366 + srfN = srfAttach,structuralPanel2_4291143804 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = baha20mmAmmo_4291141366 + partName = Part + pos = -2.97062182,8.24386978,-2.5224061 + attPos = 0,0,0 + attPos0 = -0.394756258,-0.129568338,-0.683736742 + rot = 8.88178759E-15,0,1.00000012,-8.88178928E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4291142342 + srfN = srfAttach,structuralPanel2_4291143828 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = ksp.r.largeBatteryPack_4291149656 + partName = Part + pos = -4.95362663,8.35734558,-4.50453472 + attPos = 0,0,0 + attPos0 = 0.377760649,-0.0166690387,0.65430063 + rot = -0.707106829,-1.25607405E-15,-1.3816815E-14,0.707106948 + attRot = 0,0,0,1 + attRot0 = -3.09086232E-08,0.707107067,0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4291140924 + srfN = srfAttach,structuralPanel2_4291411092 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = ksp.r.largeBatteryPack_4291140924 + partName = Part + pos = -2.19810653,8.35734653,-4.5045352 + attPos = 0,0,0 + attPos0 = 0.377759248,-0.0166690387,-0.654299676 + rot = 0.707106709,-2.96461532E-21,-1.25607481E-14,-0.707107067 + attRot = 0,0,0,1 + attRot0 = -0.707106471,-4.23516423E-22,1.25607464E-14,0.707107186 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4291149656 + srfN = srfAttach,structuralPanel2_4291411116 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = ksp.r.largeBatteryPack_4291142510 + partName = Part + pos = -4.92299032,8.35734653,-3.50311112 + attPos = 0,0,0 + attPos0 = 0.347124368,-0.0166693665,-0.347122699 + rot = -0.707106829,-1.25607405E-15,-1.3816815E-14,0.707106948 + attRot = 0,0,0,1 + attRot0 = -3.09086232E-08,0.707107067,0.70710659,3.09086303E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4291140766 + srfN = srfAttach,structuralPanel2_4291411092 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = ksp.r.largeBatteryPack_4291140766 + partName = Part + pos = -2.2287426,8.35734653,-3.50311112 + attPos = 0,0,0 + attPos0 = 0.347123265,-0.0166693665,0.347123682 + rot = 0.707106709,-2.96461532E-21,-1.25607481E-14,-0.707107067 + attRot = 0,0,0,1 + attRot0 = -0.707106471,-4.23516423E-22,1.25607464E-14,0.707107186 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = ksp.r.largeBatteryPack_4291142510 + srfN = srfAttach,structuralPanel2_4291411116 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 549.992004 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralPanel2_4290935030 + partName = Part + pos = 1.32734609,8.40677452,-1.83867145 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.91427612,-0.0166683327,5.79530251E-07 + rot = 8.34465027E-07,0,0,-1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,0,0,2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290934996 + link = baha20mmAmmo_4290934928 + link = bahaGatlingGun_4293567452 + link = bahaBrowningAnm2_4293448092 + sym = structuralPanel2_4290933658 + srfN = srfAttach,structuralPanel2_4291143506 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4290934996 + partName = Part + pos = 3.3162806,8.42344284,-1.83867264 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = 1.00000012,0,0,1.1920929E-06 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4290934962 + link = trussPiece3x_4291142878 + link = bahaTurret_4293612372 + sym = structuralPanel2_4290933618 + srfN = srfAttach,structuralPanel2_4290935030 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4290934962 + partName = Part + pos = 4.05805111,6.93154001,-1.09689283 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,-1.11265802 + rot = -1.00000012,0,0,-1.28149986E-06 + attRot = 0,0,0,0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4290933578 + srfN = srfAttach,structuralPanel2_4290934996 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = baha20mmAmmo_4290934928 + partName = Part + pos = 0.932590723,8.27720547,-2.52240729 + attPos = 0,0,0 + attPos0 = -0.394756258,-0.129568338,-0.683736742 + rot = 8.88179436E-15,5.96046448E-07,1.00000012,-8.88178589E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4290933538 + srfN = srfAttach,structuralPanel2_4290935030 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralPanel2_4290933658 + partName = Part + pos = -8.47908306,8.40677452,-1.83867097 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.91426837,-0.0166683327,-1.72185807E-07 + rot = -3.55271368E-14,-1.00000012,8.34465027E-07,4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,-8.28808102E-15,8.7422805E-08,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290933618 + link = baha20mmAmmo_4290933538 + sym = structuralPanel2_4290935030 + srfN = srfAttach,structuralPanel2_4291143482 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4290933618 + partName = Part + pos = -10.4680166,8.42344379,-1.83867192 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = 4.37114025E-08,-1.1920929E-06,-1.00000012,4.97379915E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4290933578 + link = bahaM1Abrams_4293582422 + sym = structuralPanel2_4290934996 + srfN = srfAttach,structuralPanel2_4290933658 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4290933578 + partName = Part + pos = -11.2097902,6.93154049,-1.09689283 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 1.11265802,1.50023901,-1.11265802 + rot = -1.00000012,-2.51508561E-15,-5.02429621E-15,-1.28149986E-06 + attRot = 0,0,0,0.999999881 + attRot0 = 3.66099897E-07,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4290934962 + srfN = srfAttach,structuralPanel2_4290933618 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = baha20mmAmmo_4290933538 + partName = Part + pos = -8.0843277,8.27720547,-2.52240682 + attPos = 0,0,0 + attPos0 = -0.394756258,-0.129568338,-0.683736742 + rot = 1.21936881E-14,-5.96046448E-07,-1.00000012,-2.88827774E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4290934928 + srfN = srfAttach,structuralPanel2_4290933658 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralPanel2_4290933368 + partName = Part + pos = 1.33332324,8.40735245,-3.8502388 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.95009184,-0.016668329,1.1755767E-06 + rot = 8.34465027E-07,0,0,-1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -1,0,0,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290933328 + link = baha20mmAmmo_4290933248 + sym = structuralPanel2_4290932338 + srfN = srfAttach,structuralPanel2_4291358240 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4290933328 + partName = Part + pos = 3.32225823,8.42402077,-3.85023975 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = 1.00000012,0,0,1.1920929E-06 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = structuralPanel2_4290932292 + srfN = srfAttach,structuralPanel2_4290933368 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = baha20mmAmmo_4290933248 + partName = Part + pos = 0.9385674,8.27778244,-4.53397417 + attPos = 0,0,0 + attPos0 = -0.394756258,-0.129568338,-0.683736742 + rot = 8.88179436E-15,5.96046448E-07,1.00000012,-8.88178589E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4290932200 + srfN = srfAttach,structuralPanel2_4290933368 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralPanel2_4290932338 + partName = Part + pos = -8.48506069,8.40735245,-3.85023832 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.95008361,-0.016668329,-1.47908884E-06 + rot = -3.55271368E-14,-1.00000012,8.34465027E-07,4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,-8.28808102E-15,8.7422805E-08,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290932292 + link = baha20mmAmmo_4290932200 + sym = structuralPanel2_4290933368 + srfN = srfAttach,structuralPanel2_4291357748 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4290932292 + partName = Part + pos = -10.4739943,8.42402077,-3.85023928 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = 4.37114025E-08,-1.1920929E-06,-1.00000012,4.97379915E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = structuralPanel2_4290933328 + srfN = srfAttach,structuralPanel2_4290932338 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = baha20mmAmmo_4290932200 + partName = Part + pos = -8.09030437,8.27778244,-4.53397417 + attPos = 0,0,0 + attPos0 = -0.394756258,-0.129568338,-0.683736742 + rot = 1.21936881E-14,-5.96046448E-07,-1.00000012,-2.88827774E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4290933248 + srfN = srfAttach,structuralPanel2_4290932338 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralPanel2_4290932024 + partName = Part + pos = 1.25660253,8.4072628,-5.82176781 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.83779407,-0.016668329,9.37158006E-07 + rot = 8.34465027E-07,0,0,-1.00000012 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = -1,0,0,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290931978 + link = baha20mmAmmo_4290931886 + link = bahaGoalKeeper_4293599360 + sym = structuralPanel2_4290930580 + srfN = srfAttach,structuralPanel2_4291143602 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4290931978 + partName = Part + pos = 3.245538,8.42393112,-5.82176876 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = 1.00000012,0,0,1.1920929E-06 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4290867756 + sym = structuralPanel2_4290930528 + srfN = srfAttach,structuralPanel2_4290932024 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = baha20mmAmmo_4290931886 + partName = Part + pos = 0.861846209,8.27769279,-6.50550413 + attPos = 0,0,0 + attPos0 = -0.394756258,-0.129568338,-0.683736742 + rot = 8.88179436E-15,5.96046448E-07,1.00000012,-8.88178589E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4290930424 + srfN = srfAttach,structuralPanel2_4290932024 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralPanel2_4290930580 + partName = Part + pos = -8.4083395,8.4072628,-5.82176733 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 1.83778369,-0.016668329,-2.20280413E-06 + rot = -3.55271368E-14,-1.00000012,8.34465027E-07,4.37113918E-08 + attRot = 0.499999911,0.499999911,-0.499999911,0.499999911 + attRot0 = 1,-8.28808102E-15,8.7422805E-08,-2.68220873E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralPanel2_4290930528 + link = baha20mmAmmo_4290930424 + sym = structuralPanel2_4290932024 + srfN = srfAttach,structuralPanel2_4291143578 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralPanel2_4290930528 + partName = Part + pos = -10.397274,8.42393112,-5.82176876 + attPos = -0.0130749,1.492257,7.70547715E-08 + attPos0 = 2.98340201,0.0250024796,-4.67895603E-07 + rot = 4.37114025E-08,-1.1920929E-06,-1.00000012,4.97379915E-14 + attRot = -0.499999911,0.499999911,0.499999911,0.499999911 + attRot0 = -1,0,0,-2.38418608E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = trussPiece3x_4290930476 + sym = structuralPanel2_4290931978 + srfN = srfAttach,structuralPanel2_4290930580 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = baha20mmAmmo_4290930424 + partName = Part + pos = -8.01358318,8.27769279,-6.50550413 + attPos = 0,0,0 + attPos0 = -0.394756258,-0.129568338,-0.683736742 + rot = 1.21936881E-14,-5.96046448E-07,-1.00000012,-2.88827774E-15 + attRot = 0,0,0,1 + attRot0 = -8.8817842E-15,2.38418551E-07,-1,8.88179097E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4290931886 + srfN = srfAttach,structuralPanel2_4290930580 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = trussPiece3x_4290930476 + partName = Part + pos = -11.0543594,6.93202305,-6.47884798 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0.657082438,1.49190676,-0.65708214 + rot = -1.84408221E-14,-1.07288361E-06,-1.00000012,1.47220662E-14 + attRot = 0,0,0,0.999999881 + attRot0 = -8.94069956E-08,-4.37114096E-08,1.29075658E-14,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4290867756 + srfN = srfAttach,structuralPanel2_4290930528 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4290867756 + partName = Part + pos = 3.90261865,6.93202353,-6.4788475 + attPos = -0.701286316,-0.0126867704,4.0231148E-06 + attPos0 = 0.657081842,1.49190676,0.657081664 + rot = 2.131626E-14,-9.23871994E-07,-1.00000012,-2.13162567E-14 + attRot = 0,0,0,0.999999881 + attRot0 = 2.13162753E-14,-1,-1.49011527E-07,2.13162313E-14 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = trussPiece3x_4290930476 + srfN = srfAttach,structuralPanel2_4290931978 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (1, 1, 1) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = trussPiece3x_4291142878 + partName = Part + pos = 4.01608467,9.91535187,-1.13887203 + attPos = 0,0,0 + attPos0 = 0.699804783,-1.49190736,-0.699804604 + rot = -1.1920929E-06,0,0,1.00000012 + attRot = 0,0,0,1 + attRot0 = -1,0,0,-5.68434189E-14 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaM102Howitzer_4291142854 + srfN = srfAttach,structuralPanel2_4290934996 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 75 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaM102Howitzer_4291142854 + partName = Part + pos = 3.98163819,11.1178932,-0.0400066525 + attPos = 0,0,0 + attPos0 = -0.0344468132,1.20253813,1.09886527 + rot = -9.00004185E-15,-1.00000012,1.28149986E-06,-7.10543922E-15 + attRot = 0,0,0,-0.999999881 + attRot0 = -2.36827934E-15,-1,1.49011598E-07,-7.10542651E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,trussPiece3x_4291142878 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 15 + minPitch = -15 + yawRange = 30 + minPitchLimit = -15 + maxPitchLimit = 15 + yawRangeLimit = 30 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 3500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CannonShells + amount = 20 + maxAmount = 20 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaGatlingGun_4293567452 + partName = Part + pos = 1.07709384,8.72516251,-1.58841825 + attPos = 0,0,0 + attPos0 = -0.250252962,0.31838721,0.250253499 + rot = 0,-1.00000012,9.23871994E-07,0 + attRot = 0,-0.99999994,0,0 + attRot0 = 0,1,-5.96047016E-08,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4290935030 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 65 + minPitch = -8 + yawRange = 90 + minPitchLimit = -8 + maxPitchLimit = 65 + yawRangeLimit = 90 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaM230ChainGun_4293590744 + partName = Part + pos = -0.586929083,8.46677685,-1.30654168 + attPos = 0,0,0 + attPos0 = 4.76837158E-07,-0.0766695812,-0.532128692 + rot = 0,-1.00000012,5.96046448E-07,0 + attRot = 0,-0.99999994,0,0 + attRot0 = 0,2.84217094E-14,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291143506 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 50 + minPitch = -17 + yawRange = 270 + minPitchLimit = -17 + maxPitchLimit = 50 + yawRangeLimit = 270 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDALookConstraintUp + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDALookConstraintUp + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDALookConstraintUp + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDALookConstraintUp + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDAScaleByDistance + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaTurret_4293612372 + partName = Part + pos = 2.38375783,8.53231716,-1.58880329 + attPos = 0,0,0 + attPos0 = -0.932524204,-0.108873323,-0.24986957 + rot = 0,-1.00000012,1.1920929E-06,0 + attRot = 0,-0.99999994,0,0 + attRot0 = 0,5.68434189E-14,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4290934996 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 85 + minPitch = -8 + yawRange = 360 + minPitchLimit = -8 + maxPitchLimit = 85 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaH70Turret_4293555874 + partName = Part + pos = -1.92737675,8.80024052,-1.19018018 + attPos = 0,0,0 + attPos0 = 0.648488998,0.426801831,0.648489058 + rot = -2.38418579E-07,0,0,1.00000012 + attRot = 0,0,0,1 + attRot0 = 0,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291143828 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = RocketLauncher + isEnabled = True + engageRangeMin = 0 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + active = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 35 + minPitch = -30 + yawRange = 360 + minPitchLimit = -30 + maxPitchLimit = 35 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDALookConstraintUp + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDALookConstraintUp + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = Hydra70Rocket + amount = 32 + maxAmount = 32 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaHiddenVulcan_4293534536 + partName = Part + pos = 0.0353415012,8.4167757,-2.00540733 + attPos = 0,0,0 + attPos0 = 0.622271299,-0.0266690925,0.166736528 + rot = 0,-1.00000012,5.96046448E-07,0 + attRot = 0,-0.99999994,0,0 + attRot0 = 0,2.84217094E-14,1,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291143506 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = False + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaBrowningAnm2_4293448092 + partName = Part + pos = 1.72599626,8.48450279,-1.38338423 + attPos = 0,0,0 + attPos0 = 0.398650795,0.0777271092,0.455287218 + rot = 0,-1.00000012,9.23871994E-07,0 + attRot = 0,-0.99999994,0,0 + attRot0 = 0,1,-5.96047016E-08,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4290935030 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = False + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaOMillennium_4293573334 + partName = Part + pos = -4.15941906,8.99244308,-3.60979819 + attPos = 0,0,0 + attPos0 = -0.416446328,0.618426979,-0.240436196 + rot = -2.5121481E-15,-1.00000012,2.08616257E-07,-2.5121481E-15 + attRot = 0,-0.99999994,0,0 + attRot0 = -8.94069672E-08,-4.37113847E-08,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291411092 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 75 + minPitch = -4 + yawRange = 360 + minPitchLimit = -4 + maxPitchLimit = 75 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 3800 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 3500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaGoalKeeper_4293599360 + partName = Part + pos = 1.67853189,9.33033943,-5.09096718 + attPos = 0,0,0 + attPos0 = 0.421929568,0.923075855,0.730802834 + rot = 0,-1.00000012,9.23871994E-07,0 + attRot = 0,-0.99999994,0,0 + attRot0 = 0,1,-5.96047016E-08,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4290932024 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 85 + minPitch = -15 + yawRange = 360 + minPitchLimit = -15 + maxPitchLimit = 85 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 4000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 80 + minPitch = -5 + yawRange = 360 + minPitchLimit = -5 + maxPitchLimit = 80 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaM1Abrams_4293582422 + partName = Part + pos = -9.9501009,8.6181097,-2.73573184 + attPos = 0,0,0 + attPos0 = -0.517916024,-0.194668517,-0.897060454 + rot = 1.00485924E-14,-1.00000012,1.28149986E-06,-1.50728886E-14 + attRot = 0,-0.99999994,0,0 + attRot0 = 1,1.16054424E-14,4.37113776E-08,-1.19209261E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4290933618 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 27 + minPitch = -4 + yawRange = 360 + minPitchLimit = -4 + maxPitchLimit = 27 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 3500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CannonShells + amount = 20 + maxAmount = 20 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaABL_4293539156 + partName = Part + pos = -1.14091229,8.9803524,-3.85023785 + attPos = 0,0,0 + attPos0 = -0.524144292,-0.589668214,-3.81028656E-07 + rot = -4.17232513E-07,-0.707106888,4.17232513E-07,0.707106888 + attRot = 0,-0.707106709,0,0.707106709 + attRot0 = 0.707106829,-6.61093269E-09,-0.707106829,6.61093269E-09 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291358240 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTurret + isEnabled = True + maxPitch = 90 + minPitch = -15 + yawRange = 360 + minPitchLimit = -15 + maxPitchLimit = 90 + yawRangeLimit = 360 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = True + defaultDetonationRange = 3500 + useRippleFire = True + engageRangeMin = 0 + engageRangeMax = 5000 + engageAir = True + engageMissile = True + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + } + AGFireToggle + { + actionGroup = None + } + AGFireHold + { + actionGroup = None + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 7600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileController_4291142920 + partName = Part + pos = -2.35101604,8.35459328,-6.12241793 + attPos = 0,0,0 + attPos0 = 0.224849701,-0.0193332173,-0.300656646 + rot = -5.9952056E-15,-1.00000012,4.47034836E-07,5.9952056E-15 + attRot = 0,-0.99999994,0,0 + attRot0 = 5.99520349E-15,1,-2.08616228E-07,-5.99520645E-15 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralPanel2_4291143924 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileFire + isEnabled = True + weaponIndex = 0 + targetScanInterval = 3 + fireBurstLength = 0 + guardAngle = 360 + guardRange = 5000 + gunRange = 2000 + maxMissilesOnTarget = 1 + guardMode = False + targetMissiles = False + team = False + isArmed = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggleGuardMode + { + actionGroup = Custom09 + } + AGToggleTargetType + { + actionGroup = None + } + AGJettisonWeapon + { + actionGroup = None + } + AGToggleTeam + { + actionGroup = None + } + AGToggleArm + { + actionGroup = None + } + AGFire + { + actionGroup = Custom06 + } + AGFireGunsHold + { + actionGroup = None + } + AGFireGunsToggle + { + actionGroup = None + } + AGCycle + { + actionGroup = Custom07 + } + AGCycleBack + { + actionGroup = Custom08 + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = RadarWarningReceiver + isEnabled = True + rwrEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWingCommander + isEnabled = True + savedWingmen = + spread = 50 + lag = 10 + commandSelf = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} diff --git a/BDArmory/Distribution/GameData/BDArmory/craft/BDAc_Test_Drone_MKIII.craft b/BDArmory/Distribution/GameData/BDArmory/craft/BDAc_Test_Drone_MKIII.craft new file mode 100644 index 000000000..c9e74b0a1 --- /dev/null +++ b/BDArmory/Distribution/GameData/BDArmory/craft/BDAc_Test_Drone_MKIII.craft @@ -0,0 +1,12212 @@ +ship = BDAc Test Drone MKIII +version = 1.4.5 +description = +type = SPH +size = 9.8239212,4.04665565,11.8735523 +steamPublishedFileId = 0 +persistentId = 2287204039 +rot = 0,0,0,0 +missionFlag = Squad/Flags/uk_space_agency +vesselType = Debris +PART +{ + part = probeCoreOcto2_4286473160 + partName = Part + persistentId = 1897557547 + pos = -0.149111196,6.32575798,1.16386378 + attPos = 0,0,0 + attPos0 = -0.149111196,6.32575798,1.16386378 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,0.999999881 + attRot0 = 0.707106769,0,0,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = noseConeAdapter_4285872770 + attN = bottom,noseConeAdapter_4285872770_0|-0.0610621|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleCommand + isEnabled = True + hibernation = False + hibernateOnWarp = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + MakeReferenceToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + HibernateToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSAS + isEnabled = True + standaloneToggle = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleKerbNetAccess + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OpenKerbNetAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLogisticsConsumer + isEnabled = True + lastCheck = -1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 1480 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTripLogger + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + Log + { + flight = 0 + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 5 + maxAmount = 5 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = noseConeAdapter_4285872770 + partName = Part + persistentId = 1491567360 + pos = -0.149111196,6.32575798,-0.0222103596 + attPos = 0,0,0 + attPos0 = 0,-1.1860621,1.1920929E-07 + rot = 0.707106829,0,0,0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = structuralIBeam2_4282896240 + link = fuelLine_4282892040 + attN = top,probeCoreOcto2_4286473160_0|1.125|0 + attN = bottom01,structuralIBeam2_4282896240_0|-0.75|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleAnimateHeat + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/cones/Cones + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 256 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 80 + maxAmount = 80 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = structuralIBeam2_4282896240 + partName = Part + persistentId = 2605693001 + pos = -0.149111196,6.3257575,-2.37052393 + attPos = 0,-0.00333976746,0 + attPos0 = 0,-2.34827185,8.34463776E-07 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = 0,0,0,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Heaviest + rigidAttachment = True + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = fairingSize1_4282896212 + link = MK1Fuselage_4282895208 + link = bahaCamPod_4282893472 + attN = top,noseConeAdapter_4285872770_0|1.598274|0 + attN = bottom,fairingSize1_4282896212_0|-1.598274|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 13500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Structural/structuralIBeam200/model000 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = fairingSize1_4282896212 + partName = Part + persistentId = 4139059336 + pos = -0.149111196,6.32575655,-4.17069817 + attPos = 0,0.0182547569,9.9475983E-14 + attPos0 = 0,-1.81827474,2.3841848E-07 + rot = -0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = 0,0,0,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Grandparent + rigidAttachment = True + istg = -1 + resPri = 0 + dstg = 1 + sidx = 0 + sqor = 0 + sepI = -1 + attm = 0 + modCost = 183.461945 + modMass = 0.305769891 + modSize = 0,0,0 + link = fairingSize1_4282895992 + link = rtg_4282895704 + link = rtg_4282895670 + link = structuralWing2_4282895636 + link = structuralWing2_4285359142 + link = SurfAntenna_4282892072 + attN = top,structuralIBeam2_4282896240_0|0.22|0 + attN = bottom,fairingSize1_4282895992_0|-0.2|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleProceduralFairing + isEnabled = True + interstageCraftID = 0 + nArcs = 2 + ejectionForce = 0 + useClamshell = False + stagingEnabled = False + fsm = st_idle + EVENTS + { + } + ACTIONS + { + DeployFairingAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + XSECTION + { + h = 0 + r = 0.625 + } + XSECTION + { + h = 0.200000003 + r = 0.786501706 + } + XSECTION + { + h = 2.20000005 + r = 0.786501706 + } + XSECTION + { + h = 3.59623504 + r = 0.786501706 + } + XSECTION + { + h = 5.36643648 + r = 0.637582958 + } + XSECTION + { + h = 5.9722023 + r = 0.508161843 + } + XSECTION + { + h = 6.42922783 + r = 0.364290208 + } + XSECTION + { + h = 6.89889479 + r = 0.200000003 + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCargoBay + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNodeToggle + isEnabled = True + showMesh = True + showNodes = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModulePartVariants + isEnabled = True + useVariantMass = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = fairingSize1_4282895992 + partName = Part + persistentId = 3594834583 + pos = -0.149111196,6.32575655,-3.38017368 + attPos = 0,1.19055665,-1.1920924E-07 + attPos0 = 0,-0.40000093,0 + rot = -3.09086232E-08,0.707106829,-0.707106829,-3.09086232E-08 + attRot = -6.9372962E-18,1.58706825E-10,1,4.37113918E-08 + attRot0 = 0,0,1,4.37113918E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Heaviest + rigidAttachment = True + istg = -1 + resPri = 0 + dstg = 3 + sidx = 0 + sqor = 1 + sepI = -1 + attm = 0 + modCost = 87.8748627 + modMass = 0.146458104 + modSize = 0,0,0 + link = baha20mmAmmo_4282895772 + link = baha20mmAmmo_4282895738 + attN = bottom,fairingSize1_4282896212_0|-0.2|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleProceduralFairing + isEnabled = True + interstageCraftID = 0 + nArcs = 2 + ejectionForce = 100 + useClamshell = False + stagingEnabled = False + fsm = st_idle + EVENTS + { + } + ACTIONS + { + DeployFairingAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + XSECTION + { + h = 0 + r = 0.625 + } + XSECTION + { + h = 0.200000003 + r = 0.78706032 + } + XSECTION + { + h = 1.33333778 + r = 0.78706032 + } + XSECTION + { + h = 1.9046241 + r = 0.78706032 + } + XSECTION + { + h = 2.38687587 + r = 0.657617569 + } + XSECTION + { + h = 3.23719478 + r = 0.200000003 + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCargoBay + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNode + isEnabled = True + spawnState = False + visibilityState = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStructuralNodeToggle + isEnabled = True + showMesh = True + showNodes = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModulePartVariants + isEnabled = True + useVariantMass = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = baha20mmAmmo_4282895772 + partName = Part + persistentId = 2934222295 + pos = -0.583215594,6.32575655,-3.40269375 + attPos = -0.312779665,-0.0152836088,0 + attPos0 = 0.746882498,0.0378043577,0 + rot = 0,-8.94069672E-08,0.707106948,0.707106709 + attRot = 0,0,0,1 + attRot0 = -0.49999997,-0.50000006,0.499999911,-0.500000119 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 4 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4282895738 + srfN = srfAttach,fairingSize1_4282895992 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/AmmoBox/texture20x102 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = baha20mmAmmo_4282895738 + partName = Part + persistentId = 1484548009 + pos = 0.284993351,6.32575655,-3.40269375 + attPos = 0.312779665,-0.0152830724,0 + attPos0 = -0.746882498,0.0378042236,0 + rot = -8.94069672E-08,8.94069672E-08,-0.707106948,0.70710659 + attRot = 0,0,0,1 + attRot0 = 0.5,-0.49999997,0.49999997,0.500000119 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 4 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = baha20mmAmmo_4282895772 + srfN = srfAttach,fairingSize1_4282895992 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CFEnable + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/AmmoBox/texture20x102 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = 20x102Ammo + amount = 650 + maxAmount = 650 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = rtg_4282895704 + partName = Part + persistentId = 1673693917 + pos = -0.406743944,6.32575607,-4.70754623 + attPos = 0,0,0 + attPos0 = -0.257632762,-0.536803246,0 + rot = 0.707106829,0,0,-0.707106829 + attRot = 0,0,0,1 + attRot0 = -1,0,0,0 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = rtg_4282895670 + srfN = srfAttach,fairingSize1_4282896212 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGenerator + isEnabled = True + generatorIsActive = False + throttle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCoreHeat + isEnabled = True + CoreTempGoalAdjustment = 0 + CoreThermalEnergy = 0 + stagingEnabled = True + lastUpdateTime = 0 + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 23300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = rtg_4282895670 + partName = Part + persistentId = 3571916852 + pos = 0.108521566,6.32575607,-4.70754623 + attPos = 0,0,0 + attPos0 = 0.257632762,-0.536803246,0 + rot = -0.707106888,0,0,0.707106769 + attRot = 0,0,0,1 + attRot0 = 1,0,0,8.94069672E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = rtg_4282895704 + srfN = srfAttach,fairingSize1_4282896212 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleGenerator + isEnabled = True + generatorIsActive = False + throttle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleCoreHeat + isEnabled = True + CoreTempGoalAdjustment = 0 + CoreThermalEnergy = 0 + stagingEnabled = True + lastUpdateTime = 0 + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 23300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralWing2_4282895636 + partName = Part + persistentId = 3349863326 + pos = -0.801345825,6.32575655,-4.73421097 + attPos = -5.96046448E-08,-0.785621047,0 + attPos0 = -0.652234554,0.222127825,0 + rot = 0.707106888,0,-4.21468513E-08,0.707106769 + attRot = 0,0,0,1 + attRot0 = -5.96046448E-08,2.98023224E-08,2.98023224E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon2_4282895596 + link = smallCtrlSrf_4282895556 + link = fuelLine_4291854816 + sym = structuralWing2_4285359142 + srfN = srfAttach,fairingSize1_4282896212 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4282895596 + partName = Part + persistentId = 1705424008 + pos = -3.64080811,6.32575703,-5.33421659 + attPos = -0.0148077011,0.0247831345,-2.07177209E-09 + attPos0 = -2.82465458,-0.624786615,2.42842987E-07 + rot = 0.707107067,-1.89660767E-07,1.26440511E-07,0.70710659 + attRot = 0,0,0,1 + attRot0 = 1.7881392E-07,-1.49011345E-08,2.53319712E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4285359102 + srfN = srfAttach,structuralWing2_4282895636 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = False + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = smallCtrlSrf_4282895556 + partName = Part + persistentId = 375078754 + pos = -2.27955532,6.32575703,-5.33422422 + attPos = -0.0198395252,-0.00577735901,2.55992916E-09 + attPos0 = -1.45836997,-0.594223738,2.21148611E-07 + rot = 0.707107067,-1.8966081E-07,1.26440526E-07,0.70710659 + attRot = 0,0,0,1 + attRot0 = 1.19209275E-07,-1.49011239E-08,2.53319712E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = smallCtrlSrf_4285359062 + srfN = srfAttach,structuralWing2_4282895636 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 400 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = structuralWing2_4285359142 + partName = Part + persistentId = 210627050 + pos = 0.503123403,6.32575655,-4.73421288 + attPos = 5.96046448E-08,-0.785622478,0 + attPos0 = 0.652234554,0.222127825,0 + rot = -7.30554746E-08,0.707106709,0.707106948,-3.0908609E-08 + attRot = 0,0,0,1 + attRot0 = 2.98023224E-08,-1,0,7.35137107E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = elevon2_4285359102 + link = smallCtrlSrf_4285359062 + link = fuelLine_4285359024 + link = fuelLine_4291859496 + sym = structuralWing2_4282895636 + srfN = srfAttach,fairingSize1_4282896212 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = elevon2_4285359102 + partName = Part + persistentId = 3327313628 + pos = 3.34259939,6.32575798,-5.3342185 + attPos = -0.0148077011,0.0247821808,6.68563871E-09 + attPos0 = -2.82465267,-0.62478596,-6.3874262E-07 + rot = 9.55318669E-08,0.707106531,0.707107127,-2.20569405E-07 + attRot = 0,0,0,1 + attRot0 = -1.49011584E-07,1.49010955E-08,2.53319655E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = elevon2_4282895596 + srfN = srfAttach,structuralWing2_4285359142 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = True + ignoreRoll = False + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 500 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 550 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = smallCtrlSrf_4285359062 + partName = Part + persistentId = 3318624303 + pos = 1.98134434,6.32575798,-5.33422613 + attPos = -0.0198395252,-0.00577831268,-5.32787681E-09 + attPos0 = -1.45836902,-0.594223261,-4.54898583E-07 + rot = 9.55318669E-08,0.707106531,0.707107127,-2.20569405E-07 + attRot = 0,0,0,1 + attRot0 = -1.1920929E-07,1.4901067E-08,2.53319655E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = smallCtrlSrf_4282895556 + srfN = srfAttach,structuralWing2_4285359142 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 400 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = fuelLine_4285359024 + partName = CompoundPart + persistentId = 3945231491 + pos = 0.633797586,6.32575846,-5.35922861 + attPos = 0,0,0 + attPos0 = -0.130673692,-0.625001609,2.04303973E-07 + rot = 0.500000119,0.49999997,0.50000006,-0.500000119 + attRot = 0.707106709,0,0,0.707106709 + attRot0 = 9.55319024E-08,-1.99496014E-07,0.707106829,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralWing2_4285359142 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + tgt = 4291587174 + pos = -1.81589425,-0.195421934,-0.0632168427 + rot = 0,0,0,1 + dir = -0.993663967,-0.106935725,-0.0345925614 + } + MODULE + { + name = CModuleLinkedMesh + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = CModuleFuelLine + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/FuelDuct + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = MK1Fuselage_4282895208 + partName = Part + persistentId = 4243849893 + pos = -0.149111196,6.3257575,-3.03759956 + attPos = 0,-0.917573929,0.728991687 + attPos0 = 0,0.250527829,-0.728991628 + rot = 8.38440049E-13,0.707106948,0.707106709,8.38439615E-13 + attRot = 0,0,0,1 + attRot0 = -2.71050543E-19,-1,1.78813934E-07,-1.18573294E-12 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = sweptWing2_4282895168 + link = sweptWing2_4282894432 + link = advSasModule_4282893696 + link = MK1Fuselage_4282893384 + link = bahaECMJammer_4294296078 + link = batteryPack_4287220662 + link = batteryPack_4287220076 + link = MK1Fuselage_4282892834 + link = MK1Fuselage_4291587546 + srfN = srfAttach,structuralIBeam2_4282896240 + attN = top,MK1Fuselage_4282893384_0|0.9375|0 + attN = bottom,advSasModule_4282893696_0|-0.9375|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Dynamic + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Dynamic + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Structural/mk1Parts/Mk1Structural + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 230 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = sweptWing2_4282895168 + partName = Part + persistentId = 927573374 + pos = -0.772828043,6.3257575,-3.46539116 + attPos = 4.17232513E-07,-0.486958772,1.43570389E-07 + attPos0 = 0.623714805,0.059169326,3.49157787E-08 + rot = -0.707106769,1.2644054E-07,-4.21468691E-08,-0.707106888 + attRot = 0,0,0,1 + attRot0 = 1.19209275E-07,1,-8.94069601E-08,5.96034901E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaHiddenVulcan_4282895128 + link = bahaAdjustableRail_4282895062 + link = bahaAdjustableRail_4282894960 + link = bahaAdjustableRail_4282894906 + link = bahaAdjustableRail_4282894852 + link = GearSmall_4282894738 + link = bahaAdjustableRail_4282894486 + link = IntakeRadialLong_4282891620 + link = IntakeRadialLong_4282891540 + link = IntakeRadialLong_4282891460 + link = bdPilotAI_4282891692 + sym = sweptWing2_4282894432 + srfN = srfAttach,MK1Fuselage_4282895208 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaHiddenVulcan_4282895128 + partName = Part + persistentId = 685715577 + pos = -1.127231,6.22201395,-3.09622288 + attPos = 0.100018978,2.89082527E-06,1.49011612E-08 + attPos0 = -0.454420805,0.369149655,0.10374365 + rot = 1.00000012,1.78814233E-07,1.19209133E-07,2.38418579E-07 + attRot = 0,0,0,1 + attRot0 = -0.707106709,-1.68587746E-07,1.6858769E-07,-0.707106948 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaHiddenVulcan_4282894392 + srfN = srfAttach,sweptWing2_4282895168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = False + defaultDetonationRange = 3500 + useRippleFire = False + engageEnabled = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGFireToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGFireHold + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/hiddenVulcan/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282895062 + partName = Part + persistentId = 3731269365 + pos = -1.13878918,6.19000006,-4.12561417 + attPos = 0.531555891,-0.281212628,-5.81145287E-07 + attPos0 = -0.897516489,-0.379006505,0.13575691 + rot = 0,7.10542736E-13,-4.37111325E-08,-1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -0.707106709,1.57349135E-07,-1.12382157E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = HellfireEMP_4290849048 + sym = bahaAdjustableRail_4282894326 + srfN = srfAttach,sweptWing2_4282895168 + attN = bottom,HellfireEMP_4290849048_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894960 + partName = Part + persistentId = 882018287 + pos = -2.20794654,6.19000292,-4.15098095 + attPos = 0.293717384,-0.32802701,-2.50339508E-06 + attPos0 = -1.72883034,-0.357559562,0.13575606 + rot = -1.1920929E-07,4.03233003E-13,-4.37112249E-08,-1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -0.707106709,1.57349135E-07,-1.12382157E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4280428614 + sym = bahaAdjustableRail_4282894224 + srfN = srfAttach,sweptWing2_4282895168 + attN = bottom,bahaAim120_4280428614_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894906 + partName = Part + persistentId = 2526573276 + pos = -2.78057575,6.1900034,-4.1394434 + attPos = 0.476090431,-0.315338433,-2.01165676E-06 + attPos0 = -2.48382926,-0.358711898,0.135755673 + rot = 0,-6.09290396E-13,4.3711232E-08,1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -0.707106709,1.57349135E-07,-1.12382157E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4282892974 + sym = bahaAdjustableRail_4282894170 + srfN = srfAttach,sweptWing2_4282895168 + attN = bottom,bahaAim120_4282892974_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894852 + partName = Part + persistentId = 1015970030 + pos = -4.57290077,6.32575703,-4.4654007 + attPos = -0.00800085068,-0.0862942934,-0.0494818576 + attPos0 = -3.79199982,-0.913703322,0.0494820736 + rot = 0,1.49011612E-07,0.707106709,-0.707107008 + attRot = 0,0,0,1 + attRot0 = -0.500000119,-0.499999911,-0.49999994,0.500000179 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim9_4294409322 + sym = bahaAdjustableRail_4282894116 + srfN = srfAttach,sweptWing2_4282895168 + attN = bottom,bahaAim9_4294409322_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = 0 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4282894738 + partName = Part + persistentId = 2102617926 + pos = -1.63333464,6.33675241,-4.76096725 + attPos = 0.301810741,-0.896637738,-0.104737483 + attPos0 = -1.16230512,-0.39890188,0.0937423706 + rot = 0,4.87356412E-13,4.57210062E-13,-1.00000012 + attRot = 4.2632615E-14,1.1920929E-07,-1.78814332E-07,1.00000012 + attRot0 = -0.707106709,1.26440554E-07,-4.21468407E-08,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = GearSmall_4282894002 + srfN = srfAttach,sweptWing2_4282895168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1.29999995 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = False + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + wasActiveBeforePartWasAdjusted = False + } + LightOnAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + LightOffAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894486 + partName = Part + persistentId = 330677695 + pos = -3.51542425,6.19000196,-4.15327168 + attPos = -1.1920929E-05,-0.321970403,-5.36441803E-07 + attPos0 = -2.74257064,-0.365907073,0.135756165 + rot = 0,2.38418451E-07,6.90378556E-07,-1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -0.707106709,-5.30317777E-07,-3.61730798E-07,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAGM-114_4294420192 + link = bahaAGM-114_4294420702 + sym = bahaAdjustableRail_4282893750 + srfN = srfAttach,sweptWing2_4282895168 + attN = left,bahaAGM-114_4294420192_0.04429158|-0.0235229|0.0168 + attN = right,bahaAGM-114_4294420702_-0.04429158|-0.0235229|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = sweptWing2_4282894432 + partName = Part + persistentId = 2415146514 + pos = 0.47460562,6.3257575,-3.46539211 + attPos = -4.17232513E-07,-0.486959726,1.43570787E-07 + attPos0 = -0.623714805,0.059169326,3.49187346E-08 + rot = 1.12382352E-08,0.707106829,0.707106829,-1.57349149E-07 + attRot = 0,0,0,1 + attRot0 = -2.08616228E-07,1.03317248E-07,1.1920924E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaHiddenVulcan_4282894392 + link = bahaAdjustableRail_4282894326 + link = bahaAdjustableRail_4282894224 + link = bahaAdjustableRail_4282894170 + link = bahaAdjustableRail_4282894116 + link = GearSmall_4282894002 + link = bahaAdjustableRail_4282893750 + link = IntakeRadialLong_4282891580 + link = IntakeRadialLong_4282891500 + link = IntakeRadialLong_4282891420 + link = missileController_4282891664 + sym = sweptWing2_4282895168 + srfN = srfAttach,MK1Fuselage_4282895208 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleLiftingSurface + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wings/Wings + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 500 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaHiddenVulcan_4282894392 + partName = Part + persistentId = 3663272440 + pos = 0.829011321,6.22201395,-3.09622383 + attPos = 0.100019038,3.24845314E-06,1.1920929E-07 + attPos0 = -0.454420447,0.369150132,-0.103743598 + rot = 1.00000012,-1.78814332E-07,-1.19209268E-07,2.38418579E-07 + attRot = 0,0,0,1 + attRot0 = -1.99496284E-07,-0.707107008,0.70710665,-1.99496355E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaHiddenVulcan_4282895128 + srfN = srfAttach,sweptWing2_4282894432 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWeapon + isEnabled = True + onlyFireInRange = False + defaultDetonationRange = 3500 + useRippleFire = False + engageEnabled = True + engageRangeMin = 0 + engageRangeMax = 2500 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGFireToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGFireHold + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/hiddenVulcan/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894326 + partName = Part + persistentId = 96108597 + pos = 0.840569675,6.19000101,-4.12561417 + attPos = 0.531555533,-0.281212837,5.81145287E-07 + attPos0 = -0.897515833,-0.379006237,-0.135757089 + rot = 0,2.68229883E-13,-4.37114522E-08,1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -1.68587718E-07,-0.70710665,-0.707106888,1.68587661E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = HellfireEMP_4290851070 + sym = bahaAdjustableRail_4282895062 + srfN = srfAttach,sweptWing2_4282894432 + attN = bottom,HellfireEMP_4290851070_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894224 + partName = Part + persistentId = 205108723 + pos = 1.90972412,6.19000387,-4.1509819 + attPos = 0.293716908,-0.328027457,2.44379044E-06 + attPos0 = -1.72882903,-0.357559055,-0.135756299 + rot = 1.1920929E-07,4.84945417E-13,-4.3711367E-08,1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -1.68587718E-07,-0.70710665,-0.707106888,1.68587661E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4280429494 + sym = bahaAdjustableRail_4282894960 + srfN = srfAttach,sweptWing2_4282894432 + attN = bottom,bahaAim120_4280429494_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894170 + partName = Part + persistentId = 4259665909 + pos = 2.48235464,6.19000387,-4.13944244 + attPos = 0.476090431,-0.315336496,1.96695328E-06 + attPos0 = -2.48382759,-0.358711869,-0.135755971 + rot = 0,2.68229883E-13,-4.37114522E-08,1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -1.68587718E-07,-0.70710665,-0.707106888,1.68587661E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim120_4294418360 + sym = bahaAdjustableRail_4282894906 + srfN = srfAttach,sweptWing2_4282894432 + attN = bottom,bahaAim120_4294418360_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282894116 + partName = Part + persistentId = 2164860946 + pos = 4.27468109,6.32575703,-4.4654026 + attPos = -0.00800132751,-0.086294055,0.0494818352 + attPos0 = -3.79199719,-0.913703084,-0.0494826213 + rot = 0,1.49011612E-07,0.707106709,0.707107008 + attRot = 0,0,0,1 + attRot0 = 0.499999791,0.500000119,0.500000119,-0.49999994 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAim9_4282894062 + sym = bahaAdjustableRail_4282894852 + srfN = srfAttach,sweptWing2_4282894432 + attN = bottom,bahaAim9_4282894062_0|-0.06987453|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = 0 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4282894002 + partName = Part + persistentId = 3901190789 + pos = 1.33511043,6.33675337,-4.76096916 + attPos = 0.301810265,-0.896639168,0.104737282 + attPos0 = -1.16230428,-0.398901403,-0.0937425569 + rot = 0,3.25297352E-13,7.66474828E-14,1.00000012 + attRot = 4.2632615E-14,1.1920929E-07,-1.78814332E-07,1.00000012 + attRot0 = -1.6675115E-07,0.790544152,0.612405062,2.18367688E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = GearSmall_4282894738 + srfN = srfAttach,sweptWing2_4282894432 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1.29999995 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = False + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + wasActiveBeforePartWasAdjusted = False + } + LightOnAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + LightOffAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAdjustableRail_4282893750 + partName = Part + persistentId = 2106516139 + pos = 3.21720648,6.19000196,-4.15327358 + attPos = -1.21593475E-05,-0.321971059,3.7252903E-07 + attPos0 = -2.74256873,-0.365906835,-0.135756403 + rot = 0,2.38418522E-07,6.90378727E-07,1.00000012 + attRot = -8.42936672E-08,-1.1920914E-07,-3.85446384E-07,-1 + attRot0 = -3.30822161E-07,-0.707106709,-0.707106829,4.99409396E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = bahaAGM-114_4282893274 + link = bahaAGM-114_4294421222 + sym = bahaAdjustableRail_4282894486 + srfN = srfAttach,sweptWing2_4282894432 + attN = left,bahaAGM-114_4282893274_0.04429158|-0.0235229|0.0168 + attN = right,bahaAGM-114_4294421222_-0.04429158|-0.0235229|0.0168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDAdjustableRail + isEnabled = True + railHeight = -0.099999994 + railLength = 0.400000006 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/adjustableRail/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 950 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = advSasModule_4282893696 + partName = Part + persistentId = 3182959139 + pos = -0.149111196,6.32575703,-4.17414951 + attPos = -6.2837529E-08,0.718777657,0 + attPos0 = -6.01115822E-19,-1.1365273,2.95382335E-07 + rot = -1.14239169E-26,-0.707106829,0.707106829,8.45370463E-26 + attRot = 0,0,0.99999994,0 + attRot0 = -1,3.25260626E-19,1.18573294E-12,-2.08616228E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = bottom,MK1Fuselage_4282895208_0|-0.1990267|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleReactionWheel + isEnabled = True + actuatorModeCycle = 1 + authorityLimiter = 100 + stateString = Active + stagingEnabled = True + WheelState = Active + EVENTS + { + } + ACTIONS + { + CycleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + Activate + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + Deactivate + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + Toggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 1200 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaCamPod_4282893472 + partName = Part + persistentId = 1546109071 + pos = -0.149111196,5.7872963,1.1372242 + attPos = 0,2.41290617,0.15229705 + attPos0 = 0,1.09468877,0.38616249 + rot = -2.08616257E-07,-2.16840434E-19,6.84088636E-13,1.00000012 + attRot = 0,0,0,1 + attRot0 = 0.707106948,-4.83723467E-13,-4.83723792E-13,-0.707106709 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,structuralIBeam2_4282896240 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleTargetingCamera + isEnabled = True + cameraEnabled = False + currentFovIndex = 0 + slaveTurrets = False + CoMLock = False + groundStabilized = False + savedLat = 0 + savedLong = 0 + savedAlt = 0 + nvMode = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 4000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/targetingCam/texture + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = MK1Fuselage_4282893384 + partName = Part + persistentId = 3869315438 + pos = -0.149111196,6.32575798,-1.16256917 + attPos = 0,0,0 + attPos0 = 2.12966727E-18,1.87499774,-7.45057749E-09 + rot = 0.707106829,1.82782831E-26,-1.82782831E-26,0.707106829 + attRot = 0,0,0,1 + attRot0 = -3.25260626E-19,-1,2.08616228E-07,1.18573294E-12 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = GearSmall_4282891944 + attN = bottom,MK1Fuselage_4282895208_0|-0.9375|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Dynamic + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Structural/mk1Parts/Mk1Structural + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 230 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = fuelLine_4282892040 + partName = CompoundPart + persistentId = 961778263 + pos = -0.149111211,6.56389141,-0.772223592 + attPos = 0,0,0 + attPos0 = -1.49011612E-08,-0.750000894,-0.23813273 + rot = 0.707106829,0,0.707106829,0 + attRot = 0,0,0,1 + attRot0 = 0.5,0.5,0.5,0.5 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,noseConeAdapter_4285872770 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + tgt = 4282895208 + pos = -1.32786536,0.0789591968,0.00405685464 + rot = 0,0,2.98019103E-08,1.00000226 + dir = -0.998232067,0.0593581274,0.00304976874 + } + MODULE + { + name = CModuleLinkedMesh + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = CModuleFuelLine + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/FuelDuct + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = GearSmall_4282891944 + partName = Part + persistentId = 1060319810 + pos = -0.149111196,6.04808044,-0.762576818 + attPos = 4.33680921E-19,0.488856345,-0.341628879 + attPos0 = -1.084203E-18,-0.0888597742,0.619304359 + rot = -2.38418579E-07,-1.33226763E-15,2.89251023E-09,1.00000012 + attRot = 0,0,0,1 + attRot0 = -0.707107008,2.04531259E-09,2.04531436E-09,0.70710665 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = ForceHeaviest + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,MK1Fuselage_4282893384 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleWheelBase + isEnabled = True + wheelType = FREE + isGrounded = False + autoFriction = True + frictionMultiplier = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActAutoFrictionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSuspension + isEnabled = True + springTweakable = 1 + damperTweakable = 1 + suspensionPos = (-1, -1, -1) + autoBoost = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelSteering + isEnabled = True + steeringEnabled = True + steeringInvert = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + SteeringToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelBrakes + isEnabled = True + brakeTweakable = 100 + brakeInput = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + BrakeAction + { + actionGroup = Brakes + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDeployment + isEnabled = True + shieldedCanDeploy = False + stateDisplayString = Deployed + stateString = Deployed + stagingEnabled = True + position = 1 + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = Gear + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleLookAtConstraint + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleStatusLight + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleTestSubject + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleLight + isEnabled = True + isOn = False + uiWriteLock = False + lightR = 1 + lightG = 1 + lightB = 1 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleLightAction + { + actionGroup = Light + wasActiveBeforePartWasAdjusted = False + } + LightOnAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + LightOffAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWheelDamage + isEnabled = True + isDamaged = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleDragModifier + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Wheel/LandingGear/LandingGear + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 700 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = IntakeRadialLong_4282891620 + partName = Part + persistentId = 903960252 + pos = -1.06317675,6.39737511,-3.88251686 + attPos = 0.0303322375,-0.436320603,0.0221394375 + attPos0 = -0.320675731,0.0191975832,-0.0937570706 + rot = -1.19209304E-07,2.38418579E-07,1.00000012,-1.90015996E-07 + attRot = 0,0,0,1 + attRot0 = -1.76508479E-07,-0.707106948,-0.707106709,1.76508593E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = IntakeRadialLong_4282891580 + srfN = srfAttach,sweptWing2_4282895168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/intakeRadialLong/Radial_long + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 900 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = IntakeAir + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = IntakeRadialLong_4282891580 + partName = Part + persistentId = 1091160695 + pos = 0.764952779,6.39737606,-3.88251877 + attPos = 0.0303320885,-0.436321557,-0.0221395344 + attPos0 = -0.320675492,0.0191985145,0.0937570482 + rot = 1.19209389E-07,2.38418579E-07,1.00000012,1.90015939E-07 + attRot = 0,0,0,1 + attRot0 = -0.70710665,-2.07417173E-07,-2.07417074E-07,0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = IntakeRadialLong_4282891620 + srfN = srfAttach,sweptWing2_4282894432 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/intakeRadialLong/Radial_long + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 900 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = IntakeAir + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = IntakeRadialLong_4282891540 + partName = Part + persistentId = 831361147 + pos = -1.33214736,6.39899588,-3.88128567 + attPos = 0.0195083618,-0.436063588,0.020518668 + attPos0 = -0.578826666,0.020171823,-0.0937570408 + rot = -1.19209318E-07,2.38418579E-07,1.00000012,-1.90016124E-07 + attRot = 0,0,0,1 + attRot0 = -1.76508479E-07,-0.707106948,-0.707106709,1.76508593E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = IntakeRadialLong_4282891500 + srfN = srfAttach,sweptWing2_4282895168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/intakeRadialLong/Radial_long + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 900 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = IntakeAir + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = IntakeRadialLong_4282891500 + partName = Part + persistentId = 3027940991 + pos = 1.03392601,6.39899683,-3.88128757 + attPos = 0.0195083618,-0.436064541,-0.0205187723 + attPos0 = -0.578826249,0.0201727543,0.0937569961 + rot = 1.19209346E-07,2.38418579E-07,1.00000012,1.90016095E-07 + attRot = 0,0,0,1 + attRot0 = -0.70710665,-2.07417173E-07,-2.07417074E-07,0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = IntakeRadialLong_4282891540 + srfN = srfAttach,sweptWing2_4282894432 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/intakeRadialLong/Radial_long + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 900 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = IntakeAir + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = IntakeRadialLong_4282891460 + partName = Part + persistentId = 2815131252 + pos = -1.59928203,6.39779425,-3.88074493 + attPos = 0.0794739127,-9.23871994E-07,0.0217199177 + attPos0 = -0.905917764,-0.41534996,-0.093756631 + rot = -1.19209318E-07,2.38418579E-07,1.00000012,-1.90016124E-07 + attRot = 0,0,0,1 + attRot0 = -1.76508479E-07,-0.707106948,-0.707106709,1.76508593E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = IntakeRadialLong_4282891420 + srfN = srfAttach,sweptWing2_4282895168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/intakeRadialLong/Radial_long + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 900 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = IntakeAir + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = IntakeRadialLong_4282891420 + partName = Part + persistentId = 3273022564 + pos = 1.30105793,6.3977952,-3.88074684 + attPos = 0.0794737339,-1.90734863E-06,-0.0217199102 + attPos0 = -0.905917108,-0.415349007,0.0937564522 + rot = 1.19209346E-07,2.38418579E-07,1.00000012,1.90016095E-07 + attRot = 0,0,0,1 + attRot0 = -0.70710665,-2.07417173E-07,-2.07417074E-07,0.707107008 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = IntakeRadialLong_4282891460 + srfN = srfAttach,sweptWing2_4282894432 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/intakeRadialLong/Radial_long + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 900 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleResourceIntake + isEnabled = True + intakeEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = IntakeAir + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = False + flowMode = Both + } + RESOURCE + { + name = IntakeAtm + amount = 0.5 + maxAmount = 0.5 + flowState = True + isTweakable = False + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bdPilotAI_4282891692 + partName = Part + persistentId = 2639548422 + pos = -2.00489974,6.44021225,-3.54748726 + attPos = -0.71248877,-1.08174884,3.50177288E-07 + attPos0 = -1.23206341,-0.082095772,-0.114453614 + rot = -1.88369739E-07,1.00000012,-2.38418579E-07,1.19209346E-07 + attRot = 0,0,0,1 + attRot0 = 1.75344439E-07,-0.707106709,0.707106948,1.75344312E-07 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,sweptWing2_4282895168 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = BDModulePilotAI + isEnabled = True + defaultAltitude = 2000 + minAltitude = 500 + steerMult = 8 + pitchKiAdjust = 0 + maxSteer = 1 + steerDamping = 3 + maxSpeed = 800 + takeOffSpeed = 90 + minSpeed = 80 + idleSpeed = 120 + maxAllowedGForce = 18 + maxAllowedAoA = 45 + UpToEleven = False + standbyMode = False + pilotOn = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGActivatePilot + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGDeactivatePilot + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGTogglePilot + { + actionGroup = Custom10 + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = missileController_4282891664 + partName = Part + persistentId = 3725250164 + pos = 1.61664081,6.38350201,-3.64680481 + attPos = -0.883796096,-1.07679725,-1.89989805E-07 + attPos0 = -1.1420238,-0.181412458,0.057744246 + rot = -3.38517509E-07,1.00000012,-1.1920929E-07,-1.19209282E-07 + attRot = 0,0,0,1 + attRot0 = 0.707106888,1.66312503E-07,-1.66312603E-07,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,sweptWing2_4282894432 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileFire + isEnabled = True + weaponIndex = 0 + targetScanInterval = 0.0599999987 + fireBurstLength = 1 + guardAngle = 360 + guardRange = 40000 + gunRange = 8000 + maxMissilesOnTarget = 1 + guardMode = False + team = False + isArmed = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGToggleGuardMode + { + actionGroup = Custom10 + wasActiveBeforePartWasAdjusted = False + } + AGToggleTargetType + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGJettisonWeapon + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGToggleTeam + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGToggleArm + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGFireGunsHold + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGFireGunsToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGCycle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGCycleBack + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = RadarWarningReceiver + isEnabled = True + rwrEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleWingCommander + isEnabled = True + savedWingmen = + commandSelf = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = SurfAntenna_4282892072 + partName = Part + persistentId = 3536022891 + pos = -0.149111152,6.88494873,-4.38070011 + attPos = 0,0,0 + attPos0 = 4.47034836E-08,-0.210000992,-0.559190035 + rot = 0,-0.707106829,0,-0.707106829 + attRot = 0.49999994,0.49999994,0.49999994,0.49999994 + attRot0 = -0.5,0.5,-0.5,0.5 + mir = 1,1,1 + symMethod = Radial + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,fairingSize1_4282896212 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleDataTransmitter + isEnabled = True + xmitIncomplete = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + StartTransmissionAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 1000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 300 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4282893274 + partName = Part + persistentId = 1042145317 + pos = 3.35049367,6.06647873,-4.13647461 + attPos = 0,0,0 + attPos0 = 0.133291662,-0.123522915,0.0167990215 + rot = 0,-1.1920929E-07,-0.707106948,-0.707106829 + attRot = 0.49999994,-0.49999994,-0.49999994,-0.49999994 + attRot0 = 1.73700698E-07,1.49011612E-07,-0.707106292,-0.707107306 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282893750_0|0.089|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 15 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-114R + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 500 + maxOffBoresight = 180 + DetonationDistance = 0.100000001 + dropTime = 0.400000006 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 12 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4294421222 + partName = Part + persistentId = 3703445021 + pos = 3.08391547,6.06647825,-4.13647556 + attPos = 0,0,0 + attPos0 = -0.133291483,-0.123523019,0.016797889 + rot = 0,0,-0.707106888,0.707106888 + attRot = -0.49999994,-0.49999994,-0.49999994,0.49999994 + attRot0 = 1.43898276E-07,-1.49011598E-07,-0.707107306,0.707106292 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282893750_0|0.089|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 15 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-114R + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 500 + maxOffBoresight = 180 + DetonationDistance = 0.100000001 + dropTime = 0.400000006 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 12 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4294418360 + partName = Part + persistentId = 2997783304 + pos = 2.48235512,5.9301281,-3.94764519 + attPos = 0,0,0 + attPos0 = 3.60564343E-07,-0.259874821,0.191798255 + rot = 0,1.48818945E-13,1.32542794E-13,1.00000012 + attRot = -0.707106769,0,0,0.707106769 + attRot0 = 5.21083065E-15,-2.98427922E-13,4.37113634E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894170_0|0.09|-0.175 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 25000 + minStaticLaunchRange = 500 + maxOffBoresight = 120 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 25000 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4280429494 + partName = Part + persistentId = 801400618 + pos = 1.90972412,5.9301281,-3.95918465 + attPos = 0,0,0 + attPos0 = 2.93612024E-09,-0.259874851,0.191798285 + rot = 0,2.06994185E-14,-2.01572943E-13,1.00000012 + attRot = -0.707106769,0,0,0.707106769 + attRot0 = -1.19209275E-07,-4.1922016E-13,4.37112533E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894224_0|0.09|-0.175 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 25000 + minStaticLaunchRange = 500 + maxOffBoresight = 120 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 25000 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4280428614 + partName = Part + persistentId = 353521405 + pos = -2.20794654,5.93012762,-3.95918369 + attPos = 0,0,0 + attPos0 = -9.94264369E-08,-0.259874821,0.191798195 + rot = 0,-2.81360249E-13,-2.4116535E-13,1.00000012 + attRot = -0.707106769,0,0,0.707106769 + attRot0 = 1.19209275E-07,-3.9079845E-13,4.37112071E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894960_0|0.09|-0.175 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 25000 + minStaticLaunchRange = 500 + maxOffBoresight = 120 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 25000 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim120_4282892974 + partName = Part + persistentId = 2130450134 + pos = -2.78057623,5.9301281,-3.94764519 + attPos = 0,0,0 + attPos0 = -9.94264866E-08,-0.259874821,0.191798195 + rot = 0,-1.90922934E-13,-2.11019624E-13,1.00000012 + attRot = -0.707106769,0,0,0.707106769 + attRot0 = 0,3.83693023E-13,-4.37113137E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894906_0|0.09|-0.175 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-120 + maxStaticLaunchRange = 25000 + minStaticLaunchRange = 500 + maxOffBoresight = 120 + DetonationDistance = 10.8188658 + dropTime = 0.550000012 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 25000 + engageAir = True + engageMissile = True + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 25 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4294420192 + partName = Part + persistentId = 940622812 + pos = -3.38213897,6.06647825,-4.13647366 + attPos = 0,0,0 + attPos0 = 0.13329117,-0.123523027,0.0167978816 + rot = -2.98023224E-08,0,0.707107186,0.707106709 + attRot = -0.49999994,0.49999994,0.49999994,0.49999994 + attRot0 = -2.08616228E-07,-1.75752106E-07,-0.707107246,-0.707106352 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894486_0|0.089|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 15 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-114R + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 500 + maxOffBoresight = 180 + DetonationDistance = 0.100000001 + dropTime = 0.400000006 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 12 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAGM-114_4294420702 + partName = Part + persistentId = 294209936 + pos = -3.64871621,6.06647873,-4.1364727 + attPos = 0,0,0 + attPos0 = -0.133291796,-0.123522937,0.0167990141 + rot = -5.96046448E-08,-8.94069672E-08,-0.707106948,0.707106829 + attRot = -0.49999994,-0.49999994,-0.49999994,0.49999994 + attRot0 = 1.49011612E-07,-2.35356737E-07,0.707106352,-0.707107306 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894486_0|0.089|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 15 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-114R + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 500 + maxOffBoresight = 180 + DetonationDistance = 0.100000001 + dropTime = 0.400000006 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 12 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4282894062 + partName = Part + persistentId = 3541048767 + pos = 4.40643692,6.32575703,-4.44860363 + attPos = 0,0,0 + attPos0 = 5.86774078E-08,-0.131755918,0.0167989787 + rot = 0,0,-0.707106829,-0.707106829 + attRot = 0.49999994,-0.49999994,-0.49999994,-0.49999994 + attRot0 = 1.04308128E-07,1.1920929E-07,-2.23517418E-07,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894116_0|0.06188124|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-9 + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 200 + maxOffBoresight = 90 + DetonationDistance = 9.12498474 + dropTime = 0.100000001 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 200 + engageRangeMax = 15000 + engageAir = True + engageMissile = True + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 15 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaAim9_4294409322 + partName = Part + persistentId = 2702873333 + pos = -4.70465612,6.32575703,-4.44860172 + attPos = 0,0,0 + attPos0 = -5.62960665E-08,-0.131756067,0.0167989787 + rot = 0,0,0.707106829,-0.707106829 + attRot = 0.49999994,0.49999994,0.49999994,-0.49999994 + attRot0 = -1.49011598E-07,1.04308114E-07,-2.08616228E-07,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894852_0|0.06188124|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = False + decoupleSpeed = 5 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AIM-9 + maxStaticLaunchRange = 15000 + minStaticLaunchRange = 200 + maxOffBoresight = 90 + DetonationDistance = 9.12498474 + dropTime = 0.100000001 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 200 + engageRangeMax = 15000 + engageAir = True + engageMissile = True + engageGround = False + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 15 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaECMJammer_4294296078 + partName = Part + persistentId = 2123436692 + pos = -0.149111286,5.6706481,-3.37600613 + attPos = 5.89750471E-13,-0.604050756,0.248524368 + attPos0 = 8.94047645E-08,0.26564464,-0.903632402 + rot = 2.08616257E-07,-2.13162821E-14,-4.42136106E-08,1.00000012 + attRot = 0,0,0,1 + attRot0 = 3.12628927E-08,-0.707107067,-0.70710659,-3.12628998E-08 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + srfN = srfAttach,MK1Fuselage_4282895208 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleECMJammer + isEnabled = True + jammerEnabled = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGDisable + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + AGToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 6000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/ecmJammer/tex_ecmj131 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = HellfireEMP_4290851070 + partName = Part + persistentId = 3351021387 + pos = 0.840569675,5.93112564,-4.10881519 + attPos = 0,0,0 + attPos0 = 8.01286006E-08,-0.258874923,0.0167990066 + rot = 0,1.48818945E-13,1.32542794E-13,1.00000012 + attRot = -0.707106769,0,0,0.707106769 + attRot0 = 5.21083065E-15,-2.98427922E-13,4.37113634E-08,1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282894326_0|0.089|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 15 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-114R + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 500 + maxOffBoresight = 180 + DetonationDistance = 0.100000001 + dropTime = 0.400000006 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 0.00999999978 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEMP + isEnabled = True + proximity = 50 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = HellfireEMP_4290849048 + partName = Part + persistentId = 348367126 + pos = -1.13878918,5.93112469,-4.10881519 + attPos = 0,0,0 + attPos0 = -2.76945507E-08,-0.258874863,0.016798947 + rot = 0,-5.02426131E-14,-1.10533714E-13,1.00000012 + attRot = -0.707106769,0,0,0.707106769 + attRot0 = 0,-5.5422328E-13,4.37111716E-08,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = top,bahaAdjustableRail_4282895062_0|0.089|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MissileLauncher + isEnabled = True + decoupleForward = True + decoupleSpeed = 15 + maxAltitude = 0 + terminalGuidanceShouldActivate = True + shortName = AGM-114R + maxStaticLaunchRange = 8000 + minStaticLaunchRange = 500 + maxOffBoresight = 180 + DetonationDistance = 0.100000001 + dropTime = 0.400000006 + inCargoBay = False + detonationTime = 2 + BallisticOverShootFactor = 0.699999988 + CruiseAltitude = 500 + CruiseSpeed = 300 + CruisePredictionTime = 5 + gpsSet = False + assignedGPSCoords = (0, 0, 0) + gpsTargetName = + engageEnabled = True + engageRangeMin = 500 + engageRangeMax = 8000 + engageAir = False + engageMissile = False + engageGround = True + engageSLW = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGFire + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDExplosivePart + isEnabled = True + tntMass = 0.00999999978 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ArmAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + DetonateAG + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEMP + isEnabled = True + proximity = 50 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = BDACategoryModule + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 5 + Armor = 2 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = batteryPack_4287220662 + partName = Part + persistentId = 923063552 + pos = -0.432654858,6.31472397,-2.10009623 + attPos = 0,0,0 + attPos0 = 0.283543229,0.937501192,-0.0110339215 + rot = 6.22618433E-19,1.00000012,0,-6.22618433E-19 + attRot = 0,0,0,1 + attRot0 = 0.707106709,8.38439615E-13,-8.38440049E-13,0.707106948 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = batteryPack_4287220076 + srfN = srfAttach,MK1Fuselage_4282895208 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Electrical/z-100Battery/model000 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 80 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 100 + maxAmount = 100 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = batteryPack_4287220076 + partName = Part + persistentId = 3170066778 + pos = 0.134432927,6.31472397,-2.10009623 + attPos = 0,0,0 + attPos0 = -0.283543229,0.937501192,-0.0110339215 + rot = 6.22618433E-19,1.00000012,0,-6.22618433E-19 + attRot = 0,0,0,1 + attRot0 = 0.707106709,8.38439615E-13,-8.38440049E-13,0.707106948 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = batteryPack_4287220662 + srfN = srfAttach,MK1Fuselage_4282895208 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Electrical/z-100Battery/model000 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 80 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = ElectricCharge + amount = 100 + maxAmount = 100 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = fuelLine_4291859496 + partName = CompoundPart + persistentId = 3719167455 + pos = 1.10263455,6.27670288,-5.35922289 + attPos = 0,0,0 + attPos0 = -0.599509656,-0.625003815,-0.0490541942 + rot = -2.98023224E-08,0.707106829,0,-0.707106829 + attRot = 0.999999881,0,0,0 + attRot0 = 0.50000006,0.499999881,0.500000179,0.499999911 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = fuelLine_4291854816 + srfN = srfAttach,structuralWing2_4285359142 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + tgt = 4291587546 + pos = -0.347434014,-0.0400342494,0.0506165475 + rot = 0,0.683012843,-0.1830118,0.707106888 + dir = -0.98318243,-0.11329037,0.143241748 + } + MODULE + { + name = CModuleLinkedMesh + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = CModuleFuelLine + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/FuelDuct + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = fuelLine_4291854816 + partName = CompoundPart + persistentId = 2949461476 + pos = -1.40085673,6.27670288,-5.35922289 + attPos = 0,0,0 + attPos0 = -0.599510908,-0.625005722,0.0490540303 + rot = 0,0.70710665,0,-0.707106888 + attRot = 0.999999881,0,0,0 + attRot0 = 0.500000119,0.499999821,-0.5,-0.5 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 2 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = fuelLine_4291859496 + srfN = srfAttach,structuralWing2_4282895636 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + tgt = 4282892834 + pos = -0.0388898961,-0.0322003216,-0.0485167652 + rot = -1.27824578E-08,0.683012962,0.183011413,-0.707107067 + dir = -0.555390835,-0.459856272,-0.69287318 + } + MODULE + { + name = CModuleLinkedMesh + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = CModuleFuelLine + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = DCKinc/Camo/FuelDuct + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = MK1Fuselage_4282892834 + partName = Part + persistentId = 2549751385 + pos = -0.749111235,6.3257575,-6.2376132 + attPos = -0.629503787,-2.44448185,5.43081683E-07 + attPos0 = 1.22950339,-0.755520821,3.15224867E-07 + rot = -0.5,0.500000119,0.49999997,-0.49999997 + attRot = 0,0,0,1 + attRot0 = -2.83046795E-08,0.707106769,-1.77316267E-07,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = winglet3_4282892478 + link = CanardController_4279708024 + link = SaturnAL31_4291876828 + link = bdRadome1snub_4282892282 + link = bahaCmPod_4290049890 + link = bahaChaffPod_4290049808 + link = bahaChaffPod_4293955068 + link = bahaCmPod_4293955338 + sym = MK1Fuselage_4291587546 + srfN = srfAttach,MK1Fuselage_4282895208 + attN = top,bdRadome1snub_4282892282_0|0.9375|0 + attN = bottom,SaturnAL31_4291876828_0|-0.9375|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Dynamic + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Structural/mk1Parts/Mk1Structural + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 230 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = winglet3_4282892478 + partName = Part + persistentId = 1944524852 + pos = -0.749111056,7.24982738,-6.63763809 + attPos = 0.15795368,-0.0178966522,1.78813906E-07 + attPos0 = -1.08200204,-0.382107973,0 + rot = 0.499999791,-0.500000358,-0.499999881,0.500000119 + attRot = 0,0,0,1 + attRot0 = 1.4210853E-14,0,-3.79321591E-07,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = winglet3_4291587496 + srfN = srfAttach,MK1Fuselage_4282892834 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = False + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 650 + Armor = 10 + maxHitPoints = 650 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 650 + Armor = 10 + maxHitPoints = 650 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wingletDeltaDeluxe/model000 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = CanardController_4279708024 + partName = Part + persistentId = 1218041192 + pos = -1.36991084,6.32575798,-7.15522623 + attPos = 0,0,0 + attPos0 = -3.39884508E-07,-0.917601883,0.6207968 + rot = 0.707106888,1.30925457E-08,-1.39534805E-07,0.707106769 + attRot = 0,0,0,1 + attRot0 = 3.85312298E-08,-0.707106829,2.73954527E-07,-0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = CanardController_4291587348 + srfN = srfAttach,MK1Fuselage_4282892834 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = False + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 750 + Armor = 10 + maxHitPoints = 750 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/airplaneFins/AirplaneFins + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 720 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = SaturnAL31_4291876828 + partName = Part + persistentId = 3573353521 + pos = -0.749111116,6.32575798,-7.17511606 + attPos = 0,0,0 + attPos0 = -3.97811675E-07,-0.937502265,1.94208933E-08 + rot = -0.707106769,1.0792462E-07,1.85175999E-08,-0.707106888 + attRot = 0,0,0,1 + attRot0 = -5.96046448E-08,0.707106829,0,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = 0 + resPri = 0 + dstg = 0 + sidx = 0 + sqor = 0 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = SaturnAL31_4291587174 + attN = top,MK1Fuselage_4282892834_0|0|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MultiModeEngine + isEnabled = True + runningPrimary = True + autoSwitch = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ModeAction + { + actionGroup = Custom02 + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = Custom10 + wasActiveBeforePartWasAdjusted = False + } + OnAction + { + actionGroup = Custom01 + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = True + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = False + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleGimbal + isEnabled = True + gimbalLock = False + gimbalLimiter = 100 + currentShowToggles = True + enableYaw = True + enablePitch = True + enableRoll = False + gimbalActive = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + LockAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + FreeAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + TogglePitchAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ToggleYawAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ToggleRollAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 6000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = MK1Fuselage_4291587546 + partName = Part + persistentId = 1030206826 + pos = 0.450888813,6.3257575,-6.23761702 + attPos = 0.629503787,-2.44448519,5.43080091E-07 + attPos0 = -1.22950339,-0.755521297,3.1523092E-07 + rot = 0.5,0.500000119,0.49999997,0.49999997 + attRot = 0,0,0,1 + attRot0 = -2.83046795E-08,-0.707106769,1.77316267E-07,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + link = winglet3_4291587496 + link = CanardController_4291587348 + link = SaturnAL31_4291587174 + link = bdRadome1snubGA_4290112934 + link = bahaCmPod_4290050252 + link = bahaChaffPod_4290050168 + link = bahaChaffPod_4290049632 + link = bahaCmPod_4290049544 + sym = MK1Fuselage_4282892834 + srfN = srfAttach,MK1Fuselage_4282895208 + attN = top,bdRadome1snubGA_4290112934_0|0.9375|0 + attN = bottom,SaturnAL31_4291587174_0|-0.9375|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 2500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Dynamic + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Structural/mk1Parts/Mk1Structural + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 1.25 + defaultScale = 1.25 + defaultTransformScale = (0, 0, 0) + DryCost = 230 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = LiquidFuel + amount = 400 + maxAmount = 400 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = winglet3_4291587496 + partName = Part + persistentId = 3844294261 + pos = 0.450888634,7.24982738,-6.63764095 + attPos = 0.15795368,-0.0178966522,1.78813906E-07 + attPos0 = -1.08200204,-0.382107973,0 + rot = -0.5,0.500000179,0.499999702,-0.500000358 + attRot = 0,0,0,1 + attRot0 = 1.4210853E-14,0,-3.79321591E-07,-1 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = winglet3_4282892478 + srfN = srfAttach,MK1Fuselage_4291587546 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = True + ignoreYaw = False + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 650 + Armor = 10 + maxHitPoints = 650 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 650 + Armor = 10 + maxHitPoints = 650 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/wingletDeltaDeluxe/model000 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 600 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = CanardController_4291587348 + partName = Part + persistentId = 3938196048 + pos = 1.07168853,6.32575798,-7.15522909 + attPos = 0,0,0 + attPos0 = -3.39884508E-07,-0.917601883,0.6207968 + rot = -1.39533171E-07,0.707106709,0.707106948,1.30942723E-08 + attRot = 0,0,0,1 + attRot0 = 3.85312298E-08,-0.707106829,2.73954527E-07,-0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = CanardController_4279708024 + srfN = srfAttach,MK1Fuselage_4291587546 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleControlSurface + isEnabled = True + mirrorDeploy = True + usesMirrorDeploy = True + ignorePitch = False + ignoreYaw = True + ignoreRoll = True + deploy = False + deployInvert = False + partDeployInvert = False + authorityLimiter = 100 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ActionToggle + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionExtend + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActionRetract + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 3000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 750 + Armor = 10 + maxHitPoints = 750 + ArmorThickness = 10 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = Squad/Parts/Aero/airplaneFins/AirplaneFins + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = TweakScale + isEnabled = True + currentScale = 100 + defaultScale = 100 + defaultTransformScale = (0, 0, 0) + DryCost = 720 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = SaturnAL31_4291587174 + partName = Part + persistentId = 321816821 + pos = 0.450888693,6.32575798,-7.17511892 + attPos = 0,0,0 + attPos0 = -3.97811675E-07,-0.937502265,1.94208933E-08 + rot = 0.707106829,1.07922943E-07,1.85159053E-08,0.707106829 + attRot = 0,0,0,1 + attRot0 = -5.96046448E-08,0.707106829,0,0.707106829 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = 0 + resPri = 0 + dstg = 0 + sidx = 0 + sqor = 0 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = SaturnAL31_4291876828 + attN = top,MK1Fuselage_4291587546_0|0|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = MultiModeEngine + isEnabled = True + runningPrimary = True + autoSwitch = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ModeAction + { + actionGroup = Custom02 + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = Custom10 + wasActiveBeforePartWasAdjusted = False + } + OnAction + { + actionGroup = Custom01 + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = True + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = None + active = False + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleEnginesFX + isEnabled = False + staged = False + flameout = False + EngineIgnited = False + engineShutdown = False + currentThrottle = 0 + thrustPercentage = 100 + manuallyOverridden = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + OnAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ShutdownAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ActivateAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleAnimateThrottle + isEnabled = True + animState = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleGimbal + isEnabled = True + gimbalLock = False + gimbalLimiter = 100 + currentShowToggles = True + enableYaw = True + enablePitch = True + enableRoll = False + gimbalActive = False + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + ToggleAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + LockAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + FreeAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + TogglePitchAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ToggleYawAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + ToggleRollAction + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = FXModuleConstrainPosition + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleAlternator + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = ModuleSurfaceFX + isEnabled = True + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 6000 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bdRadome1snub_4282892282 + partName = Part + persistentId = 4048655240 + pos = -0.749111414,6.3257575,-4.81851196 + attPos = 8.76169557E-19,-3.4489758,2.03507057E-06 + attPos0 = -2.9740562E-07,1.4190979,-1.20238525E-07 + rot = -0.707106829,8.53512682E-13,8.23366982E-13,-0.707106829 + attRot = 0,0,0,-0.999999881 + attRot0 = -2.98023224E-08,0.707106829,-1.19209275E-07,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = bottom01,MK1Fuselage_4282892834_0|-0.4816|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + TargetNext + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + TargetPrev + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 4500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = DCKtextureswitch2 + isEnabled = True + selectedTexture = 0 + selectedTextureURL = BDArmory/Parts/radome125/tex_radome125 + selectedMapURL = + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bdRadome1snubGA_4290112934 + partName = Part + persistentId = 1759755713 + pos = 0.450888991,6.3257575,-4.81851578 + attPos = 0,0,0 + attPos0 = 2.9740562E-07,1.4190979,-1.20238525E-07 + rot = 0.707106829,-8.20854723E-13,-8.56024941E-13,0.707106829 + attRot = 0,0,0,1 + attRot0 = -2.98023046E-08,-0.707106829,1.1920929E-07,0.707106769 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 0 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + attN = bottom01,MK1Fuselage_4291587546_0|-0.4816|0 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = ModuleRadar + isEnabled = True + linkedVesselID = + radarEnabled = False + rangeIndex = 99 + currentAngle = 0 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGEnable + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + TargetNext + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + TargetPrev + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 4500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } +} +PART +{ + part = bahaCmPod_4290050252 + partName = Part + persistentId = 1936624667 + pos = 0.955591023,5.82105541,-7.02841139 + attPos = 0,0,0 + attPos0 = -0.504701972,-0.790795386,0.504702032 + rot = 0.923879683,0.382683516,0,3.57627869E-07 + attRot = 0,0,0,1 + attRot0 = 0.653281331,-0.270598143,0.270597994,0.653281748 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4290049890 + srfN = srfAttach,MK1Fuselage_4291587546 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 40 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4290049890 + partName = Part + persistentId = 1201392393 + pos = -1.25381339,5.82105541,-7.02841139 + attPos = 0,0,0 + attPos0 = 0.504701972,-0.790799201,0.504702032 + rot = 0.923879743,-0.382683456,-1.49011612E-08,1.49011612E-07 + attRot = 0,0,0,1 + attRot0 = -0.653281331,-0.270598143,0.270598084,-0.653281629 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4290050252 + srfN = srfAttach,MK1Fuselage_4282892834 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 40 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4290050168 + partName = Part + persistentId = 3894955188 + pos = 0.955560863,5.82108545,-6.74903679 + attPos = 0,0,0 + attPos0 = -0.504671931,-0.511418283,0.504671812 + rot = 0.923879683,0.382683516,0,3.57627869E-07 + attRot = 0,0,0,1 + attRot0 = 0.653281331,-0.270598143,0.270597994,0.653281748 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4290049808 + srfN = srfAttach,MK1Fuselage_4291587546 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4290049808 + partName = Part + persistentId = 2598254510 + pos = -1.25378323,5.82108545,-6.74903679 + attPos = 0,0,0 + attPos0 = 0.504671931,-0.511422098,0.504671812 + rot = 0.923879743,-0.382683456,-1.49011612E-08,1.49011612E-07 + attRot = 0,0,0,1 + attRot0 = -0.653281331,-0.270598143,0.270598084,-0.653281629 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4290050168 + srfN = srfAttach,MK1Fuselage_4282892834 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4293955068 + partName = Part + persistentId = 1165003489 + pos = -1.25378036,6.83042717,-6.74537992 + attPos = 0,0,0 + attPos0 = -0.504668713,-0.507766426,0.504668772 + rot = -0.382683516,0.923879743,0,1.34110451E-07 + attRot = 0,0,0,1 + attRot0 = 0.65328151,-0.270598084,0.270597994,0.653281569 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4290049632 + srfN = srfAttach,MK1Fuselage_4282892834 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaChaffPod_4290049632 + partName = Part + persistentId = 245907638 + pos = 0.955558002,6.83042717,-6.74537992 + attPos = 0,0,0 + attPos0 = 0.504668713,-0.507762611,0.504668772 + rot = 0.382683516,0.923879743,0,-1.34110451E-07 + attRot = 0,0,0,1 + attRot0 = 0.65328151,0.270598084,-0.270597994,0.653281569 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaChaffPod_4293955068 + srfN = srfAttach,MK1Fuselage_4291587546 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMChaff + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4293955338 + partName = Part + persistentId = 231942562 + pos = -1.25393271,6.8305788,-7.02309942 + attPos = 0,0,0 + attPos0 = -0.504821301,-0.785486042,0.504821777 + rot = -0.382683516,0.923879743,0,1.34110451E-07 + attRot = 0,0,0,1 + attRot0 = 0.65328151,-0.270598084,0.270597994,0.653281569 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4290049544 + srfN = srfAttach,MK1Fuselage_4282892834 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 40 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} +PART +{ + part = bahaCmPod_4290049544 + partName = Part + persistentId = 3836647648 + pos = 0.955710351,6.8305788,-7.02309942 + attPos = 0,0,0 + attPos0 = 0.504821301,-0.785482228,0.504821777 + rot = 0.382683516,0.923879743,0,-1.34110451E-07 + attRot = 0,0,0,1 + attRot0 = 0.65328151,0.270598084,-0.270597994,0.653281569 + mir = 1,1,1 + symMethod = Mirror + autostrutMode = Off + rigidAttachment = False + istg = -1 + resPri = 0 + dstg = 0 + sidx = -1 + sqor = -1 + sepI = -1 + attm = 1 + modCost = 0 + modMass = 0 + modSize = 0,0,0 + sym = bahaCmPod_4293955338 + srfN = srfAttach,MK1Fuselage_4291587546 + EVENTS + { + } + ACTIONS + { + } + PARTDATA + { + } + MODULE + { + name = CMDropper + isEnabled = True + ejectVelocity = 40 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + AGDropCM + { + actionGroup = None + wasActiveBeforePartWasAdjusted = False + } + } + UPGRADESAPPLIED + { + } + } + MODULE + { + name = HitpointTracker + isEnabled = True + Hitpoints = 500 + Armor = 10 + maxHitPoints = 0 + ArmorThickness = 0 + ArmorSet = True + ExplodeMode = Never + FireFX = True + FireFXLifeTimeInSeconds = 5 + stagingEnabled = True + EVENTS + { + } + ACTIONS + { + } + UPGRADESAPPLIED + { + } + } + RESOURCE + { + name = CMFlare + amount = 42 + maxAmount = 42 + flowState = True + isTweakable = True + hideFlow = False + isVisible = True + flowMode = Both + } +} diff --git a/BahaTurret/bin/Release/defaultSettings.cfg b/BDArmory/Distribution/GameData/BDArmory/settings.cfg similarity index 54% rename from BahaTurret/bin/Release/defaultSettings.cfg rename to BDArmory/Distribution/GameData/BDArmory/settings.cfg index 8558604e5..2b7ba7098 100644 --- a/BahaTurret/bin/Release/defaultSettings.cfg +++ b/BDArmory/Distribution/GameData/BDArmory/settings.cfg @@ -1,15 +1,20 @@ BDASettings { INSTAKILL = False + INFINITE_AMMO = False BULLET_HITS = True - PHYSICS_RANGE = 5000 EJECT_SHELLS = True - INFINITE_AMMO = False + SHELL_COLLISIONS = True + RECOIL_FACTOR = 0.75 + PHYSICS_RANGE = 200000 + MAX_BULLET_RANGE = 8000 + MAX_GUARD_VISUAL_RANGE = 200000 + MAX_ACTIVE_RADAR_RANGE = 200000 + MAX_ENGAGEMENT_RANGE = 200000 DRAW_DEBUG_LINES = False DRAW_AIMERS = True AIM_ASSIST = True REMOTE_SHOOTING = False - DMG_MULTIPLIER = 100 FLARE_CHANCE_FACTOR = 25 BOMB_CLEARANCE_CHECK = True SMART_GUARDS = True @@ -19,30 +24,41 @@ BDASettings BW_TARGET_CAM = True SMOKE_DEFLECTION_FACTOR = 10 FLARE_THERMAL = 1350 + RWR_WINDOW_SIZE = 1.0 + RADAR_WINDOW_SIZE = 1.0 BDARMORY_UI_VOLUME = 0.35 BDARMORY_WEAPONS_VOLUME = 0.45 GLOBAL_LIFT_MULTIPLIER = 0.25 GLOBAL_DRAG_MULTIPLIER = 6 IVA_LOWPASS_FREQ = 2500 - MAX_BULLET_RANGE = 8000 PEACE_MODE = False - MAX_GUARD_VISUAL_RANGE = 5000 - SHELL_COLLISIONS = True + MAX_FIRES_PER_VESSEL = 10 + FIRELIFETIME_IN_SECONDS = 90 + PERFORMANCE_LOGGING = false + IGNORE_TERRAIN_CHECK = false + HITPOINT_MULTIPLIER = 3.0 + DMG_MULTIPLIER = 100 + BALLISTIC_DMG_FACTOR = 1.55 + EXP_DMG_MOD_BALLISTIC = 1.125 + EXP_DMG_MOD_MISSILE = 6.75 + EXP_IMP_MOD = 0.250 + ADVANCED_EDIT = true + SHOW_CATEGORIES = True } BDAInputSettings { WEAP_FIRE_KEY = mouse 0 - TGP_SLEW_RIGHT = - TGP_SLEW_LEFT = - TGP_SLEW_UP = - TGP_SLEW_DOWN = - TGP_LOCK = - TGP_IN = - TGP_OUT = - TGP_RADAR = - TGP_SEND_GPS = - TGP_TO_GPS = - TGP_TURRETS = + TGP_SLEW_RIGHT = [6] + TGP_SLEW_LEFT = [4] + TGP_SLEW_UP = [5] + TGP_SLEW_DOWN = [8] + TGP_LOCK = [9] + TGP_IN = [0] + TGP_OUT = [.] + TGP_RADAR = [3] + TGP_SEND_GPS = [7] + TGP_TO_GPS = [2] + TGP_TURRETS = [1] TGP_COM = TGP_NV = TGP_RESET = @@ -56,4 +72,8 @@ BDAInputSettings RADAR_RANGE_UP = RADAR_RANGE_DN = RADAR_CYCLE_LOCK = + RADAR_TARGET_NEXT = + RADAR_TARGT_PREV = + VS_SWITCH_NEXT = page up + VS_SWITCH_PREV = page down } diff --git a/BDArmory/FX/BDAGaplessParticleEmitter.cs b/BDArmory/FX/BDAGaplessParticleEmitter.cs new file mode 100644 index 000000000..eed6c0dd8 --- /dev/null +++ b/BDArmory/FX/BDAGaplessParticleEmitter.cs @@ -0,0 +1,112 @@ +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.FX +{ + public class BDAGaplessParticleEmitter : MonoBehaviour + { + public KSPParticleEmitter pEmitter; + private float maxDistance = 0.6f; + public bool emit = false; + public Part part = null; + public Rigidbody rb; + Vector3 internalVelocity; + Vector3 lastPos; + bool useInternalV; + + Vector3 velocity + { + get + { + if (rb) + { + return rb.velocity; + } + else if (part) + { + return part.rb.velocity; + } + else + { + useInternalV = true; + return internalVelocity; + } + } + } + + void Start() + { + pEmitter = gameObject.GetComponent(); + pEmitter.emit = false; + EffectBehaviour.AddParticleEmitter(pEmitter); + } + + void OnEnable() + { + lastPos = transform.position; + } + + void FixedUpdate() + { + if (!part && !rb) + { + internalVelocity = (transform.position - lastPos) / Time.fixedDeltaTime; + lastPos = transform.position; + if (emit && internalVelocity.sqrMagnitude > 562500) + { + return; //dont bridge gap if floating origin shifted + } + } + + if (emit) + { + maxDistance = Mathf.Clamp((pEmitter.minSize / 3), 0.3f, 5f) + + (Mathf.Clamp((BDArmorySetup.numberOfParticleEmitters - 1), 0, 20) * 0.07f); + + Vector3 originalLocalPosition = gameObject.transform.localPosition; + Vector3 originalPosition = gameObject.transform.position; + + Vector3 startPosition = gameObject.transform.position; + if (useInternalV) + { + startPosition -= (velocity * Time.fixedDeltaTime); + } + else + { + startPosition += (velocity * Time.fixedDeltaTime); + } + float originalGapDistance = Vector3.Distance(originalPosition, startPosition); + float intermediateSteps = originalGapDistance / maxDistance; + + pEmitter.EmitParticle(); + gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, startPosition, + maxDistance); + for (int i = 1; i < intermediateSteps; i++) + { + pEmitter.EmitParticle(); + gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, startPosition, + maxDistance); + } + gameObject.transform.localPosition = originalLocalPosition; + } + } + + public void EmitParticles() + { + Vector3 originalLocalPosition = gameObject.transform.localPosition; + Vector3 originalPosition = gameObject.transform.position; + Vector3 startPosition = gameObject.transform.position + (velocity * Time.fixedDeltaTime); + float originalGapDistance = Vector3.Distance(originalPosition, startPosition); + float intermediateSteps = originalGapDistance / maxDistance; + + //gameObject.transform.position = startPosition; + for (int i = 0; i < intermediateSteps; i++) + { + pEmitter.EmitParticle(); + gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, startPosition, + maxDistance); + } + gameObject.transform.localPosition = originalLocalPosition; + } + } +} diff --git a/BDArmory/FX/BDAParticleSelfDestruct.cs b/BDArmory/FX/BDAParticleSelfDestruct.cs new file mode 100644 index 000000000..5abbd4498 --- /dev/null +++ b/BDArmory/FX/BDAParticleSelfDestruct.cs @@ -0,0 +1,44 @@ +using System.Collections; +using UnityEngine; + +namespace BDArmory.FX +{ + public class BDAParticleSelfDestruct : MonoBehaviour + { + KSPParticleEmitter pEmitter; + BDAGaplessParticleEmitter gpe; + + void Awake() + { + pEmitter = gameObject.GetComponent(); + EffectBehaviour.AddParticleEmitter(pEmitter); + gpe = gameObject.GetComponent(); + } + + void Start() + { + if (pEmitter.ps.particleCount == 0) + { + Destroy(gameObject); + } + else + { + StartCoroutine(SelfDestructRoutine()); + } + } + + IEnumerator SelfDestructRoutine() + { + pEmitter.emit = false; + EffectBehaviour.RemoveParticleEmitter(pEmitter); + if (gpe) + { + gpe.emit = false; + EffectBehaviour.RemoveParticleEmitter(gpe.pEmitter); + } + yield return new WaitForSeconds(pEmitter.maxEnergy / 10); + Destroy(gameObject); + yield break; + } + } +} diff --git a/BDArmory/FX/BulletHitFX.cs b/BDArmory/FX/BulletHitFX.cs new file mode 100644 index 000000000..8f34f7c4b --- /dev/null +++ b/BDArmory/FX/BulletHitFX.cs @@ -0,0 +1,307 @@ +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Misc; +using UniLinq; +using UnityEngine; + +namespace BDArmory.FX +{ + public class BulletHitFX : MonoBehaviour + { + KSPParticleEmitter[] pEmitters; + AudioSource audioSource; + AudioClip hitSound; + public Vector3 normal; + float startTime; + public bool ricochet; + public float caliber; + + public GameObject bulletHoleDecalPrefab; + public static ObjectPool decalPool_small; + public static ObjectPool decalPool_large; + public static Dictionary> PartsOnFire = new Dictionary>(); + public static Queue HitsLoaded = new Queue(); + + public static int MaxFiresPerVessel = 3; + public static float FireLifeTimeInSeconds = 5f; + + private bool disabled = false; + + public static void SetupShellPool() + { + GameObject templateShell_large; + templateShell_large = + Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/bulletDecal/BulletDecal2")); + templateShell_large.SetActive(false); + if (decalPool_large == null) + decalPool_large = ObjectPool.CreateObjectPool(templateShell_large, BDArmorySettings.MAX_NUM_BULLET_DECALS, true, true); + + GameObject templateShell_small; + templateShell_small = + Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/bulletDecal/BulletDecal1")); + templateShell_small.SetActive(false); + if (decalPool_small == null) + decalPool_small = ObjectPool.CreateObjectPool(templateShell_small, BDArmorySettings.MAX_NUM_BULLET_DECALS, true, true); + } + + public static void SpawnDecal(RaycastHit hit, Part hitPart, float caliber, float penetrationfactor) + { + if (!BDArmorySettings.BULLET_DECALS) return; + ObjectPool decalPool_; + + if (caliber >= 90f) + { + decalPool_ = decalPool_large; + } + else + { + decalPool_ = decalPool_small; + } + + //front hit + GameObject decalFront = decalPool_.GetPooledObject(); + if (decalFront != null && hitPart != null) + { + decalFront.transform.SetParent(hitPart.transform); + decalFront.transform.position = hit.point + new Vector3(0.25f, 0f, 0f); + decalFront.transform.rotation = Quaternion.FromToRotation(Vector3.forward, hit.normal); + decalFront.SetActive(true); + } + //back hole if fully penetrated + if (penetrationfactor >= 1) + { + GameObject decalBack = decalPool_.GetPooledObject(); + if (decalBack != null && hitPart != null) + { + decalBack.transform.SetParent(hitPart.transform); + decalBack.transform.position = hit.point + new Vector3(-0.25f, 0f, 0f); + decalBack.transform.rotation = Quaternion.FromToRotation(Vector3.forward, hit.normal); + decalBack.SetActive(true); + } + + if (CanFlamesBeAttached(hitPart)) + { + AttachFlames(hit, hitPart, caliber); + } + } + } + + private static bool CanFlamesBeAttached(Part hitPart) + { + if (!BDArmorySettings.FIRE_FX_IN_FLIGHT && !hitPart.vessel.LandedOrSplashed || !hitPart.HasFuel()) + return false; + + if (hitPart.vessel.LandedOrSplashed) + { + MaxFiresPerVessel = BDArmorySettings.MAX_FIRES_PER_VESSEL; + FireLifeTimeInSeconds = BDArmorySettings.FIRELIFETIME_IN_SECONDS; + } + + if (PartsOnFire.ContainsKey(hitPart.vessel) && PartsOnFire[hitPart.vessel].Count >= MaxFiresPerVessel) + { + var firesOnVessel = PartsOnFire[hitPart.vessel]; + + firesOnVessel.Where(x => (Time.time - x) > FireLifeTimeInSeconds).Select(x => firesOnVessel.Remove(x)); + return false; + } + + if (!PartsOnFire.ContainsKey(hitPart.vessel)) + { + List firesList = new List { Time.time }; + + PartsOnFire.Add(hitPart.vessel, firesList); + } + else + { + PartsOnFire[hitPart.vessel].Add(Time.time); + } + + return true; + } + + void Start() + { + HitsLoaded.Enqueue(this); + if (decalPool_large == null || decalPool_small == null) + SetupShellPool(); + + startTime = Time.time; + pEmitters = gameObject.GetComponentsInChildren(); + + IEnumerator pe = pEmitters.AsEnumerable().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + EffectBehaviour.AddParticleEmitter(pe.Current); + } + + pe.Dispose(); + + audioSource = gameObject.AddComponent(); + audioSource.minDistance = 1; + audioSource.maxDistance = 50; + audioSource.spatialBlend = 1; + audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + + int random = Random.Range(1, 3); + + if (ricochet) + { + if (caliber <= 30) + { + string path = "BDArmory/Sounds/ricochet" + random; + hitSound = GameDatabase.Instance.GetAudioClip(path); + } + else + { + string path = "BDArmory/Sounds/Artillery_Shot"; + hitSound = GameDatabase.Instance.GetAudioClip(path); + } + } + else + { + if (caliber <= 30) + { + string path = "BDArmory/Sounds/bulletHit" + random; + hitSound = GameDatabase.Instance.GetAudioClip(path); + } + else + { + string path = "BDArmory/Sounds/Artillery_Shot"; + hitSound = GameDatabase.Instance.GetAudioClip(path); + } + } + + audioSource.PlayOneShot(hitSound); + } + + void Update() + { + using (new PerformanceLogger("BulletHitFX.Update")) + { + if (!disabled && Time.time - startTime > 0.03f) + { + IEnumerator pe = pEmitters.AsEnumerable().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + pe.Current.emit = false; + } + pe.Dispose(); + disabled = true; + } + if (Time.time - startTime > 0.3f) + { + HitsLoaded.Dequeue(); + Destroy(gameObject); + } + } + } + + public static void CreateBulletHit(Part hitPart, Vector3 position, RaycastHit hit, Vector3 normalDirection, + bool ricochet, float caliber, float penetrationfactor) + { + if (HitsLoaded.Count > 5) return; + + if (decalPool_large == null || decalPool_small == null) + SetupShellPool(); + + GameObject go; + + if (caliber <= 30) + { + go = GameDatabase.Instance.GetModel("BDArmory/Models/bulletHit/bulletHit"); + } + else + { + go = GameDatabase.Instance.GetModel("BDArmory/FX/PenFX"); + } + + if ((hitPart != null) && caliber != 0 && !hitPart.IgnoreDecal()) + { + SpawnDecal(hit, hitPart, caliber, penetrationfactor); //No bullet decals for laser or ricochet + } + + GameObject newExplosion = + (GameObject)Instantiate(go, position, Quaternion.LookRotation(normalDirection)); + newExplosion.SetActive(true); + newExplosion.AddComponent(); + newExplosion.GetComponent().ricochet = ricochet; + newExplosion.GetComponent().caliber = caliber; + IEnumerator pe = newExplosion.GetComponentsInChildren().Cast().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + pe.Current.emit = true; + + if (pe.Current.gameObject.name == "sparks") + { + pe.Current.force = (4.49f * FlightGlobals.getGeeForceAtPosition(position)); + } + else if (pe.Current.gameObject.name == "smoke") + { + pe.Current.force = (1.49f * FlightGlobals.getGeeForceAtPosition(position)); + } + } + pe.Dispose(); + } + + public static void AttachFlames(RaycastHit hit, Part hitPart, float caliber) + { + var modelUrl = "BDArmory/FX/FlameEffect2/model"; + + var flameObject = + (GameObject) + Instantiate( + GameDatabase.Instance.GetModel(modelUrl), + hit.point + new Vector3(0.25f, 0f, 0f), + Quaternion.identity); + + flameObject.SetActive(true); + flameObject.transform.SetParent(hitPart.transform); + flameObject.AddComponent(); + + if (hitPart.vessel.LandedOrSplashed && hitPart.GetFireFX() && caliber >= 100f) + { + DecalEmitterScript.shrinkRateFlame = 0.25f; + DecalEmitterScript.shrinkRateSmoke = 0.125f; + } + + foreach (var pe in flameObject.GetComponentsInChildren()) + { + if (!pe.useWorldSpace) continue; + var gpe = pe.gameObject.AddComponent(); + gpe.Emit = true; + } + } + + public static void AttachFlames(Vector3 contactPoint, Part hitPart) + { + if (!CanFlamesBeAttached(hitPart)) return; + + var modelUrl = "BDArmory/FX/FlameEffect2/model"; + + var flameObject = + (GameObject) + Instantiate( + GameDatabase.Instance.GetModel(modelUrl), + contactPoint, + Quaternion.identity); + + flameObject.SetActive(true); + flameObject.transform.SetParent(hitPart.transform); + flameObject.AddComponent(); + + DecalEmitterScript.shrinkRateFlame = 0.125f; + DecalEmitterScript.shrinkRateSmoke = 0.125f; + + foreach (var pe in flameObject.GetComponentsInChildren()) + { + if (!pe.useWorldSpace) continue; + var gpe = pe.gameObject.AddComponent(); + gpe.Emit = true; + } + } + } +} diff --git a/BDArmory/FX/CameraBulletRenderer.cs b/BDArmory/FX/CameraBulletRenderer.cs new file mode 100644 index 000000000..61401d09e --- /dev/null +++ b/BDArmory/FX/CameraBulletRenderer.cs @@ -0,0 +1,32 @@ +using BDArmory.Bullets; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.FX +{ + public class CameraBulletRenderer : MonoBehaviour + { + public float resizeFactor = 1; + Camera cam; + + void Awake() + { + cam = GetComponent(); + } + + void OnPreRender() + { + if (ModuleWeapon.bulletPool) + { + for (int i = 0; i < ModuleWeapon.bulletPool.size; i++) + { + if (ModuleWeapon.bulletPool.GetPooledObject(i).activeInHierarchy) + { + PooledBullet pBullet = ModuleWeapon.bulletPool.GetPooledObject(i).GetComponent(); + pBullet.UpdateWidth(cam, resizeFactor); + } + } + } + } + } +} diff --git a/BDArmory/FX/DecalEmitterScript.cs b/BDArmory/FX/DecalEmitterScript.cs new file mode 100644 index 000000000..5bd134105 --- /dev/null +++ b/BDArmory/FX/DecalEmitterScript.cs @@ -0,0 +1,69 @@ +using UnityEngine; + +namespace BDArmory.FX +{ + public class DecalEmitterScript : MonoBehaviour + { + //public static float _maxCombineDistance = 0.6f; + + public static float shrinkRateFlame = 2.0f; + + public static float shrinkRateSmoke = 2.25f; + + private GameObject _destroyer; + + private float _destroyTimerStart; + + private float _highestEnergy; + + public void Start() + { + foreach (var pe in gameObject.GetComponentsInChildren()) + { + var color = pe.material.color; + color.a = color.a / 2; + pe.material.SetColor("_TintColor", color); + pe.force = -FlightGlobals.getGeeForceAtPosition(transform.position) / 3; + if (!(pe.maxEnergy > _highestEnergy)) continue; + _destroyer = pe.gameObject; + _highestEnergy = pe.maxEnergy; + EffectBehaviour.AddParticleEmitter(pe); + } + } + + public void FixedUpdate() + { + if (_destroyTimerStart != 0 && Time.time - _destroyTimerStart > _highestEnergy) + { + Destroy(gameObject); + } + + foreach (var pe in gameObject.GetComponentsInChildren()) + { + var shrinkRate = pe.gameObject.name.Contains("smoke") ? shrinkRateSmoke : shrinkRateFlame; + pe.maxSize = Mathf.MoveTowards(pe.maxSize, 0, shrinkRate * Time.fixedDeltaTime); + pe.minSize = Mathf.MoveTowards(pe.minSize, 0, shrinkRate * Time.fixedDeltaTime); + + if (pe.maxSize < 0.1f && pe.gameObject == _destroyer && _destroyTimerStart == 0) + { + _destroyTimerStart = Time.time; + } + + var lightComponent = pe.gameObject.GetComponent(); + + if (lightComponent != null) + { + lightComponent.intensity = Random.Range(0f, pe.maxSize / 6); + } + } + } + + private void OnDestroy() + { + foreach (var pe in gameObject.GetComponentsInChildren()) + { + EffectBehaviour.RemoveParticleEmitter(pe); + } + } + } +} diff --git a/BDArmory/FX/DecalGaplessParticleEmitter.cs b/BDArmory/FX/DecalGaplessParticleEmitter.cs new file mode 100644 index 000000000..5833c5ec2 --- /dev/null +++ b/BDArmory/FX/DecalGaplessParticleEmitter.cs @@ -0,0 +1,110 @@ +using UnityEngine; + +namespace BDArmory.FX +{ + public class DecalGaplessParticleEmitter : MonoBehaviour + { + public bool Emit; + public float MaxDistance = 1.1f; + public Part part; + public KSPParticleEmitter PEmitter; + public Rigidbody rb; + Vector3 internalVelocity; + Vector3 lastPos; + + Vector3 velocity + { + get + { + if (rb) + { + return rb.velocity; + } + else if (part) + { + return part.rb.velocity; + } + else + { + return internalVelocity; + } + } + } + + private void Start() + { + PEmitter = gameObject.GetComponent(); + PEmitter.emit = false; + + if (part != null) + { + //Debug.Log("Part " + Part.partName + "'s explosionPotential: " + Part.explosionPotential); + } + + MaxDistance = PEmitter.minSize / 3; + } + + void OnEnable() + { + lastPos = transform.position; + } + + private void FixedUpdate() + { + if (!part && !rb) + { + internalVelocity = (transform.position - lastPos) / Time.fixedDeltaTime; + lastPos = transform.position; + if (PEmitter.emit && internalVelocity.sqrMagnitude > 562500) + { + return; //dont bridge gap if floating origin shifted + } + } + + if (!Emit) return; + + //var velocity = part?.GetComponent().velocity ?? rb.velocity; + var originalLocalPosition = gameObject.transform.localPosition; + var originalPosition = gameObject.transform.position; + var startPosition = gameObject.transform.position + velocity * Time.fixedDeltaTime; + var originalGapDistance = Vector3.Distance(originalPosition, startPosition); + var intermediateSteps = originalGapDistance / MaxDistance; + + PEmitter.EmitParticle(); + gameObject.transform.position = Vector3.MoveTowards( + gameObject.transform.position, + startPosition, + MaxDistance); + for (var i = 1; i < intermediateSteps; i++) + { + PEmitter.EmitParticle(); + gameObject.transform.position = Vector3.MoveTowards( + gameObject.transform.position, + startPosition, + MaxDistance); + } + gameObject.transform.localPosition = originalLocalPosition; + } + + public void EmitParticles() + { + var velocity = part?.GetComponent().velocity ?? rb.velocity; + var originalLocalPosition = gameObject.transform.localPosition; + var originalPosition = gameObject.transform.position; + var startPosition = gameObject.transform.position + velocity * Time.fixedDeltaTime; + var originalGapDistance = Vector3.Distance(originalPosition, startPosition); + var intermediateSteps = originalGapDistance / MaxDistance; + + //gameObject.transform.position = startPosition; + for (var i = 0; i < intermediateSteps; i++) + { + PEmitter.EmitParticle(); + gameObject.transform.position = Vector3.MoveTowards( + gameObject.transform.position, + startPosition, + MaxDistance); + } + gameObject.transform.localPosition = originalLocalPosition; + } + } +} diff --git a/BDArmory/FX/ExplosionFX.cs b/BDArmory/FX/ExplosionFX.cs new file mode 100644 index 000000000..462f3fc19 --- /dev/null +++ b/BDArmory/FX/ExplosionFX.cs @@ -0,0 +1,464 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Core.Utils; +using BDArmory.Misc; +using UnityEngine; + +namespace BDArmory.FX +{ + public class ExplosionFx : MonoBehaviour + { + public KSPParticleEmitter[] PEmitters { get; set; } + public Light LightFx { get; set; } + public float StartTime { get; set; } + public AudioClip ExSound { get; set; } + public AudioSource AudioSource { get; set; } + private float MaxTime { get; set; } + public float Range { get; set; } + public float Caliber { get; set; } + public bool IsMissile { get; set; } + public float Power { get; set; } + public Vector3 Position { get; set; } + public Vector3 Direction { get; set; } + public Part ExplosivePart { get; set; } + + public float TimeIndex => Time.time - StartTime; + + public Queue ExplosionEvents = new Queue(); + + public static List IgnoreParts = new List(); + + public static List IgnoreBuildings = new List(); + + internal static readonly float ExplosionVelocity = 343f; + + private float particlesMaxEnergy; + + public static Queue ExplosionsLoaded = new Queue(); + + private void Start() + { + ExplosionsLoaded.Enqueue(this); + StartTime = Time.time; + MaxTime = (Range / ExplosionVelocity) * 3f; + CalculateBlastEvents(); + PEmitters = gameObject.GetComponentsInChildren(); + IEnumerator pe = PEmitters.AsEnumerable().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + EffectBehaviour.AddParticleEmitter(pe.Current); + pe.Current.emit = true; + if (pe.Current.maxEnergy > particlesMaxEnergy) + { + particlesMaxEnergy = pe.Current.maxEnergy; + } + } + pe.Dispose(); + + LightFx = gameObject.AddComponent(); + LightFx.color = Misc.Misc.ParseColor255("255,238,184,255"); + LightFx.intensity = 8; + LightFx.range = Range * 3f; + LightFx.shadows = LightShadows.None; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log( + "[BDArmory]:Explosion started tntMass: {" + Power + "} BlastRadius: {" + Range + "} StartTime: {" + StartTime + "}, Duration: {" + MaxTime + "}"); + } + } + + private void CalculateBlastEvents() + { + var temporalEventList = new List(); + + temporalEventList.AddRange(ProcessingBlastSphere()); + + //Let's convert this temporal list on a ordered queue + using (var enuEvents = temporalEventList.OrderBy(e => e.TimeToImpact).GetEnumerator()) + { + while (enuEvents.MoveNext()) + { + if (enuEvents.Current == null) continue; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log( + "[BDArmory]: Enqueueing Blast Event"); + } + + ExplosionEvents.Enqueue(enuEvents.Current); + } + } + } + + private List ProcessingBlastSphere() + { + List result = new List(); + List parstAdded = new List(); + List bulidingAdded = new List(); + + using (var hitCollidersEnu = Physics.OverlapSphere(Position, Range, 9076737).AsEnumerable().GetEnumerator()) + { + while (hitCollidersEnu.MoveNext()) + { + if (hitCollidersEnu.Current == null) continue; + + Part partHit = hitCollidersEnu.Current.GetComponentInParent(); + + if (partHit != null && partHit.mass > 0 && !parstAdded.Contains(partHit)) + { + ProcessPartEvent(partHit, result, parstAdded); + } + else + { + DestructibleBuilding building = hitCollidersEnu.Current.GetComponentInParent(); + + if (building != null && !bulidingAdded.Contains(building)) + { + ProcessBuildingEvent(building, result, bulidingAdded); + } + } + } + } + return result; + } + + private void ProcessBuildingEvent(DestructibleBuilding building, List eventList, List bulidingAdded) + { + Ray ray = new Ray(Position, building.transform.position - Position); + RaycastHit rayHit; + if (Physics.Raycast(ray, out rayHit, Range, 557057)) + { + //TODO: Maybe we are not hitting building because we are hitting explosive parts. + + DestructibleBuilding destructibleBuilding = rayHit.collider.GetComponentInParent(); + + // Is not a direct hit, because we are hitting a different part + if (destructibleBuilding != null && destructibleBuilding.Equals(building)) + { + var distance = Vector3.Distance(Position, rayHit.point); + eventList.Add(new BuildingBlastHitEvent() { Distance = Vector3.Distance(Position, rayHit.point), Building = building, TimeToImpact = distance / ExplosionVelocity }); + bulidingAdded.Add(building); + } + } + } + + private void ProcessPartEvent(Part part, List eventList, List partsAdded) + { + RaycastHit hit; + float distance = 0; + if (IsInLineOfSight(part, ExplosivePart, out hit, out distance)) + { + if (IsAngleAllowed(Direction, hit)) + { + //Adding damage hit + eventList.Add(new PartBlastHitEvent() + { + Distance = distance, + Part = part, + TimeToImpact = distance / ExplosionVelocity, + HitPoint = hit.point, + }); + partsAdded.Add(part); + } + } + } + + private bool IsAngleAllowed(Vector3 direction, RaycastHit hit) + { + if (IsMissile || direction == default(Vector3)) + { + return true; + } + + return Vector3.Angle(direction, (hit.point - Position).normalized) < 100f; + } + + /// + /// This method will calculate if there is valid line of sight between the explosion origin and the specific Part + /// In order to avoid collisions with the same missile part, It will not take into account those parts beloging to same vessel that contains the explosive part + /// + /// + /// + /// out property with the actual hit + /// + private bool IsInLineOfSight(Part part, Part explosivePart, out RaycastHit hit, out float distance) + { + Ray partRay = new Ray(Position, part.transform.position - Position); + + var hits = Physics.RaycastAll(partRay, Range, 9076737).AsEnumerable(); + using (var hitsEnu = hits.OrderBy(x => x.distance).GetEnumerator()) + { + while (hitsEnu.MoveNext()) + { + Part partHit = hitsEnu.Current.collider.GetComponentInParent(); + if (partHit == null) continue; + hit = hitsEnu.Current; + distance = Vector3.Distance(Position, hit.point); + if (partHit == part) + { + return true; + } + if (partHit != part) + { + // ignoring collisions against the explosive + if (explosivePart != null && partHit.vessel == explosivePart.vessel) + { + continue; + } + // if there are parts in between but we still inside the critical sphere of damage. + if (distance <= 0.1f * Range) + { + continue; + } + + return false; + } + } + } + + hit = new RaycastHit(); + distance = 0; + return false; + } + + public void Update() + { + LightFx.intensity -= 12 * Time.deltaTime; + if (TimeIndex > 0.2f) + { + IEnumerator pe = PEmitters.AsEnumerable().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + pe.Current.emit = false; + } + pe.Dispose(); + } + + if (ExplosionEvents.Count == 0 && TimeIndex > 2f * MaxTime) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log( + "[BDArmory]:Explosion Finished"); + } + + ExplosionsLoaded.Dequeue(); + Destroy(gameObject); + return; + } + } + + public void FixedUpdate() + { + //floating origin and velocity offloading corrections + if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) + { + transform.position -= FloatingOrigin.OffsetNonKrakensbane; + } + + while (ExplosionEvents.Count > 0 && ExplosionEvents.Peek().TimeToImpact <= TimeIndex) + { + BlastHitEvent eventToExecute = ExplosionEvents.Dequeue(); + + var partBlastHitEvent = eventToExecute as PartBlastHitEvent; + if (partBlastHitEvent != null) + { + ExecutePartBlastEvent(partBlastHitEvent); + } + else + { + ExecuteBuildingBlastEvent((BuildingBlastHitEvent)eventToExecute); + } + } + } + + private void ExecuteBuildingBlastEvent(BuildingBlastHitEvent eventToExecute) + { + //TODO: Review if the damage is sensible after so many changes + //buildings + DestructibleBuilding building = eventToExecute.Building; + building.damageDecay = 600f; + + if (building) + { + var distanceFactor = Mathf.Clamp01((Range - eventToExecute.Distance) / Range); + float damageToBuilding = (BDArmorySettings.DMG_MULTIPLIER / 100) * BDArmorySettings.EXP_DMG_MOD_BALLISTIC * Power * distanceFactor; + + damageToBuilding *= 2f; + + building.AddDamage(damageToBuilding); + + if (building.Damage > building.impactMomentumThreshold) + { + building.Demolish(); + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Explosion hit destructible building! Hitpoints Applied: " + Mathf.Round(damageToBuilding) + + ", Building Damage : " + Mathf.Round(building.Damage) + + " Building Threshold : " + building.impactMomentumThreshold); + } + } + } + + private void ExecutePartBlastEvent(PartBlastHitEvent eventToExecute) + { + if (eventToExecute.Part == null || eventToExecute.Part.Rigidbody == null || eventToExecute.Part.vessel == null || eventToExecute.Part.partInfo == null) return; + + try + { + Part part = eventToExecute.Part; + Rigidbody rb = part.Rigidbody; + var realDistance = eventToExecute.Distance; + + if (!eventToExecute.IsNegativePressure) + { + BlastInfo blastInfo = + BlastPhysicsUtils.CalculatePartBlastEffects(part, realDistance, + part.vessel.totalMass * 1000f, Power, Range); + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log( + "[BDArmory]: Executing blast event Part: {" + part.name + "}, " + + " VelocityChange: {" + blastInfo.VelocityChange + "}," + + " Distance: {" + realDistance + "}," + + " TotalPressure: {" + blastInfo.TotalPressure + "}," + + " Damage: {" + blastInfo.Damage + "}," + + " EffectiveArea: {" + blastInfo.EffectivePartArea + "}," + + " Positive Phase duration: {" + blastInfo.PositivePhaseDuration + "}," + + " Vessel mass: {" + Math.Round(part.vessel.totalMass * 1000f) + "}," + + " TimeIndex: {" + TimeIndex + "}," + + " TimePlanned: {" + eventToExecute.TimeToImpact + "}," + + " NegativePressure: {" + eventToExecute.IsNegativePressure + "}"); + } + + // Add Reverse Negative Event + ExplosionEvents.Enqueue(new PartBlastHitEvent() + { + Distance = Range - realDistance, + Part = part, + TimeToImpact = 2 * (Range / ExplosionVelocity) + (Range - realDistance) / ExplosionVelocity, + IsNegativePressure = true, + NegativeForce = blastInfo.VelocityChange * 0.25f + }); + + AddForceAtPosition(rb, + (eventToExecute.HitPoint + part.rb.velocity * TimeIndex - Position).normalized * + blastInfo.VelocityChange * + BDArmorySettings.EXP_IMP_MOD, + eventToExecute.HitPoint + part.rb.velocity * TimeIndex); + + part.AddExplosiveDamage(blastInfo.Damage, + Caliber, IsMissile); + } + else + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log( + "[BDArmory]: Executing blast event Part: {" + part.name + "}, " + + " VelocityChange: {" + eventToExecute.NegativeForce + "}," + + " Distance: {" + realDistance + "}," + + " Vessel mass: {" + Math.Round(part.vessel.totalMass * 1000f) + "}," + + " TimeIndex: {" + TimeIndex + "}," + + " TimePlanned: {" + eventToExecute.TimeToImpact + "}," + + " NegativePressure: {" + eventToExecute.IsNegativePressure + "}"); + } + AddForceAtPosition(rb, (Position - part.transform.position).normalized * eventToExecute.NegativeForce * BDArmorySettings.EXP_IMP_MOD * 0.25f, part.transform.position); + } + } + catch + { + // ignored due to depending on previous event an object could be disposed + } + } + + public static void CreateExplosion(Vector3 position, float tntMassEquivalent, string explModelPath, string soundPath, bool isMissile = true, float caliber = 0, Part explosivePart = null, Vector3 direction = default(Vector3)) + { + if (ExplosionsLoaded.Count > 5) return; + var go = GameDatabase.Instance.GetModel(explModelPath); + var soundClip = GameDatabase.Instance.GetAudioClip(soundPath); + + Quaternion rotation; + if (direction == default(Vector3)) + { + rotation = Quaternion.LookRotation(VectorUtils.GetUpDirection(position)); + } + else + { + rotation = Quaternion.LookRotation(direction); + } + + GameObject newExplosion = (GameObject)Instantiate(go, position, rotation); + ExplosionFx eFx = newExplosion.AddComponent(); + eFx.ExSound = soundClip; + eFx.AudioSource = newExplosion.AddComponent(); + eFx.AudioSource.minDistance = 200; + eFx.AudioSource.maxDistance = 5500; + eFx.AudioSource.spatialBlend = 1; + eFx.Range = BlastPhysicsUtils.CalculateBlastRange(tntMassEquivalent); + eFx.Position = position; + eFx.Power = tntMassEquivalent; + eFx.IsMissile = isMissile; + eFx.Caliber = caliber; + eFx.ExplosivePart = explosivePart; + eFx.Direction = direction; + + if (tntMassEquivalent <= 5) + { + eFx.AudioSource.minDistance = 4f; + eFx.AudioSource.maxDistance = 3000; + eFx.AudioSource.priority = 9999; + } + newExplosion.SetActive(true); + IEnumerator pe = newExplosion.GetComponentsInChildren().Cast() + .GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + pe.Current.emit = true; + } + pe.Dispose(); + } + + public static void AddForceAtPosition(Rigidbody rb, Vector3 force, Vector3 position) + { + ////////////////////////////////////////////////////////// + // Add The force to part + ////////////////////////////////////////////////////////// + if (rb == null) return; + rb.AddForceAtPosition(force, position, ForceMode.VelocityChange); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Force Applied | Explosive : " + Math.Round(force.magnitude, 2)); + } + } + } + + public abstract class BlastHitEvent + { + public float Distance { get; set; } + public float TimeToImpact { get; set; } + public bool IsNegativePressure { get; set; } + } + + internal class PartBlastHitEvent : BlastHitEvent + { + public Part Part { get; set; } + public Vector3 HitPoint { get; set; } + public float NegativeForce { get; set; } + } + + internal class BuildingBlastHitEvent : BlastHitEvent + { + public DestructibleBuilding Building { get; set; } + } +} diff --git a/BDArmory/FX/ParticleTurbulence.cs b/BDArmory/FX/ParticleTurbulence.cs new file mode 100644 index 000000000..a4f9bdc58 --- /dev/null +++ b/BDArmory/FX/ParticleTurbulence.cs @@ -0,0 +1,60 @@ +using BDArmory.Misc; +using UnityEngine; + +namespace BDArmory.FX +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class ParticleTurbulence : MonoBehaviour + { + public static Vector3 flareTurbulence = Vector3.zero; + float flareTurbulenceX; + float flareTurbulenceY; + float flareTurbulenceZ; + float flareTurbDelta = 0.2f; + float flareTurbTimer; + + public static Vector3 Turbulence + { + get + { + float x = VectorUtils.FullRangePerlinNoise(Time.time * 0.5F, 0); + float y = VectorUtils.FullRangePerlinNoise(Time.time * 1.1f, 35); + float z = VectorUtils.FullRangePerlinNoise(Time.time * 0.75f, 70); + return new Vector3(x, y, z) * 5; + } + } + + void FixedUpdate() + { + //if(BDArmorySetup.numberOfParticleEmitters > 0) + //{ + if (Time.time - flareTurbTimer > flareTurbDelta) + { + flareTurbTimer = Time.time; + + if (flareTurbulenceX >= 1) flareTurbulenceX = Mathf.Clamp(1 - Random.Range(0f, 2f), 0, 1); + else if (flareTurbulenceX <= -1) + flareTurbulenceX = Mathf.Clamp(-1 + Random.Range(0f, 2f), -1, 1); + else flareTurbulenceX += Mathf.Clamp(Random.Range(-1f, 1f), -1, 1); + + if (flareTurbulenceY >= 1) flareTurbulenceY = Mathf.Clamp(1 - Random.Range(0f, 2f), 0, 1); + else if (flareTurbulenceY <= -1) + flareTurbulenceY = Mathf.Clamp(-1 + Random.Range(0f, 2f), -1, 1); + else flareTurbulenceY += Mathf.Clamp(Random.Range(-1f, 1f), -1, 1); + + if (flareTurbulenceZ >= 1) flareTurbulenceZ = Mathf.Clamp(1 - Random.Range(0f, 2f), 0, 1); + else if (flareTurbulenceZ <= -1) + flareTurbulenceZ = Mathf.Clamp(-1 + Random.Range(0f, 2f), -1, 1); + else flareTurbulenceZ += Mathf.Clamp(Random.Range(-1f, 1f), -1, 1); + } + + flareTurbulence = Vector3.Lerp(flareTurbulence, + new Vector3(flareTurbulenceX, flareTurbulenceY, flareTurbulenceZ), + Random.Range(2.5f, 7.5f) * TimeWarp.fixedDeltaTime); + + //wind + + //} + } + } +} diff --git a/BDArmory/FX/ShellCasing.cs b/BDArmory/FX/ShellCasing.cs new file mode 100644 index 000000000..e4068146b --- /dev/null +++ b/BDArmory/FX/ShellCasing.cs @@ -0,0 +1,78 @@ +using BDArmory.Core; +using UnityEngine; + +namespace BDArmory.FX +{ + public class ShellCasing : MonoBehaviour + { + public float startTime; + public Vector3 initialV; + + Vector3 velocity; + Vector3 angularVelocity; + + float atmDensity; + + void OnEnable() + { + startTime = Time.time; + velocity = initialV; + velocity += transform.rotation * + new Vector3(Random.Range(-.1f, .1f), Random.Range(-.1f, .1f), + Random.Range(6f, 8f)); + angularVelocity = + new Vector3(Random.Range(-10f, 10f), Random.Range(-10f, 10f), + Random.Range(-10f, 10f)) * 10; + + atmDensity = + (float) + FlightGlobals.getAtmDensity( + FlightGlobals.getStaticPressure(transform.position, FlightGlobals.currentMainBody), + FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody); + } + + void FixedUpdate() + { + if (!gameObject.activeInHierarchy) + { + return; + } + + //gravity + velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * TimeWarp.fixedDeltaTime + + Krakensbane.GetLastCorrection(); + + //drag + velocity -= 0.005f * (velocity + Krakensbane.GetFrameVelocityV3f()) * atmDensity; + + transform.rotation *= Quaternion.Euler(angularVelocity * TimeWarp.fixedDeltaTime); + transform.position += velocity * TimeWarp.deltaTime; + + if (BDArmorySettings.SHELL_COLLISIONS) + { + RaycastHit hit; + if (Physics.Linecast(transform.position, transform.position + velocity * Time.fixedDeltaTime, out hit, + 557057)) + { + velocity = Vector3.Reflect(velocity, hit.normal); + velocity *= 0.55f; + velocity = Quaternion.AngleAxis(Random.Range(0f, 90f), Random.onUnitSphere) * + velocity; + } + } + } + + void Update() + { + if (!gameObject.activeInHierarchy) + { + return; + } + + if (Time.time - startTime > 2) + { + gameObject.SetActive(false); + } + } + } +} diff --git a/BDArmory/Guidances/BallisticGuidance.cs b/BDArmory/Guidances/BallisticGuidance.cs new file mode 100644 index 000000000..1da643604 --- /dev/null +++ b/BDArmory/Guidances/BallisticGuidance.cs @@ -0,0 +1,127 @@ +using System; +using BDArmory.Core.Extension; +using BDArmory.Misc; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Guidances +{ + class BallisticGuidance : IGuidance + { + private Vector3 _startPoint; + private double _originalDistance = float.MinValue; + + + public Vector3 GetDirection(MissileBase missile, Vector3 targetPosition) + { + //set up + if (_originalDistance == float.MinValue) + { + _startPoint = missile.vessel.CoM; + _originalDistance = Vector3.Distance(targetPosition, missile.vessel.CoM); + } + + var surfaceDistanceVector = Vector3 + .Project((missile.vessel.CoM - _startPoint), (targetPosition - _startPoint).normalized); + + var pendingDistance = _originalDistance - surfaceDistanceVector.magnitude; + + if (missile.TimeIndex < 1) + { + return missile.vessel.CoM + missile.vessel.Velocity() * 10; + } + + Vector3 agmTarget; + + if (missile.vessel.verticalSpeed > 0 && pendingDistance > _originalDistance * 0.5) + { + missile.debugString.Append($"Ascending"); + missile.debugString.Append(Environment.NewLine); + + var freeFallTime = CalculateFreeFallTime(missile); + missile.debugString.Append($"freeFallTime: {freeFallTime}"); + missile.debugString.Append(Environment.NewLine); + + var futureDistanceVector = Vector3 + .Project((missile.vessel.GetFuturePosition() - _startPoint), (targetPosition - _startPoint).normalized); + + var futureHorizontalSpeed = CalculateFutureHorizontalSpeed(missile); + + var horizontalTime = (_originalDistance - futureDistanceVector.magnitude) / futureHorizontalSpeed; + + + missile.debugString.Append($"horizontalTime: {horizontalTime}"); + missile.debugString.Append(Environment.NewLine); + + if (freeFallTime >= horizontalTime) + { + missile.debugString.Append($"Free fall achieved:"); + missile.debugString.Append(Environment.NewLine); + + missile.Throttle = Mathf.Clamp(missile.Throttle - 0.001f, 0.01f, 1f); + + } + else + { + missile.debugString.Append($"Free fall not achieved:"); + missile.debugString.Append(Environment.NewLine); + + missile.Throttle = Mathf.Clamp(missile.Throttle + 0.001f, 0.01f, 1f); + + } + + Vector3 dToTarget = targetPosition - missile.vessel.CoM; + Vector3 direction = Quaternion.AngleAxis(Mathf.Clamp(missile.maxOffBoresight * 0.9f, 0, missile.BallisticAngle), Vector3.Cross(dToTarget, VectorUtils.GetUpDirection(missile.vessel.CoM))) * dToTarget; + agmTarget = missile.vessel.CoM + direction; + + + missile.debugString.Append($"Throttle: {missile.Throttle}"); + missile.debugString.Append(Environment.NewLine); + } + else + { + missile.debugString.Append($"Descending"); + missile.debugString.Append(Environment.NewLine); + agmTarget = MissileGuidance.GetAirToGroundTarget(targetPosition, missile.vessel, 1.85f); + + missile.Throttle = Mathf.Clamp((float)(missile.vessel.atmDensity * 10f), 0.01f, 1f); + } + + if (missile is BDModularGuidance) + { + if (missile.vessel.InVacuum()) + { + missile.vessel.Autopilot.SetMode(VesselAutopilot.AutopilotMode.Prograde); + agmTarget = missile.vessel.CoM + missile.vessel.Velocity() * 100; + } + else + { + missile.vessel.Autopilot.SetMode(VesselAutopilot.AutopilotMode.StabilityAssist); + } + } + return agmTarget; + } + + private double CalculateFreeFallTime(MissileBase missile, int predictionTime = 10) + { + double vi = CalculateFutureVerticalSpeed(missile, predictionTime) * -1; + double a = 9.80665f * missile.BallisticOverShootFactor; + double d = missile.vessel.GetFutureAltitude(predictionTime); + + double time1 = (-vi + Math.Sqrt(Math.Pow(vi, 2) - 4 * (0.5f * a) * (-d))) / a; + double time2 = (-vi - Math.Sqrt(Math.Pow(vi, 2) - 4 * (0.5f * a) * (-d))) / a; + + return Math.Max(time1, time2); + } + + private double CalculateFutureHorizontalSpeed(MissileBase missile,int predictionTime = 10) + { + return missile.vessel.horizontalSrfSpeed + (missile.HorizontalAcceleration / Time.fixedDeltaTime) * predictionTime; + } + + private double CalculateFutureVerticalSpeed(MissileBase missile, int predictionTime = 10) + { + return missile.vessel.verticalSpeed + (missile.VerticalAcceleration / Time.fixedDeltaTime) * predictionTime; + } + } +} diff --git a/BDArmory/Guidances/CruiseGuidance.cs b/BDArmory/Guidances/CruiseGuidance.cs new file mode 100644 index 000000000..ce190bd3a --- /dev/null +++ b/BDArmory/Guidances/CruiseGuidance.cs @@ -0,0 +1,346 @@ +using System; +using BDArmory.Core.Extension; +using BDArmory.Misc; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Guidances +{ + public enum GuidanceState + { + Ascending, + Cruising, + Descending, + Terminal + } + + public enum PitchDecision + { + Ascent, + Descent, + Hold, + EmergencyAscent + } + + public enum ThrottleDecision + { + Increase, + Decrease, + Hold + } + + public class CruiseGuidance : IGuidance + { + private readonly MissileBase _missile; + + + private float _pitchAngle; + private double _futureAltitude; + private double _futureSpeed; + private double _horizontalAcceleration; + + private float _lastDataRead; + private double _lastHorizontalSpeed; + private double _lastSpeedDelta; + private double _lastVerticalSpeed; + + private double _verticalAcceleration; + + private Vector3 planarDirectionToTarget; + private Vector3 upDirection; + + public CruiseGuidance(MissileBase missile) + { + _missile = missile; + } + + public ThrottleDecision ThrottleDecision { get; set; } + public PitchDecision PitchDecision { get; set; } + + public GuidanceState GuidanceState { get; set; } + + public Vector3 GetDirection(MissileBase missile, Vector3 targetPosition) + { + //set up + if (_missile.TimeIndex < 1) + return _missile.vessel.CoM + _missile.vessel.Velocity() * 10; + + upDirection = VectorUtils.GetUpDirection(_missile.vessel.CoM); + + planarDirectionToTarget = + Vector3.ProjectOnPlane(targetPosition - _missile.vessel.CoM, upDirection).normalized; + + // Ascending + _missile.debugString.Append("State=" + GuidanceState); + _missile.debugString.Append(Environment.NewLine); + + var missileAltitude = GetCurrentAltitude(_missile.vessel); + _missile.debugString.Append("Altitude=" + missileAltitude); + _missile.debugString.Append(Environment.NewLine); + + _missile.debugString.Append("Apoapsis=" + _missile.vessel.orbit.ApA); + _missile.debugString.Append(Environment.NewLine); + + _missile.debugString.Append("Future Altitude=" + _futureAltitude); + _missile.debugString.Append(Environment.NewLine); + + _missile.debugString.Append("Pitch angle=" + _pitchAngle); + _missile.debugString.Append(Environment.NewLine); + + _missile.debugString.Append("Pitch decision=" + PitchDecision); + _missile.debugString.Append(Environment.NewLine); + + _missile.debugString.Append("lastVerticalSpeed=" + _lastVerticalSpeed); + _missile.debugString.Append(Environment.NewLine); + + _missile.debugString.Append("verticalAcceleration=" + _verticalAcceleration); + _missile.debugString.Append(Environment.NewLine); + + GetTelemetryData(); + + switch (GuidanceState) + { + case GuidanceState.Ascending: + UpdateThrottle(); + + if (MissileWillReachAltitude(missileAltitude)) + { + _pitchAngle = 0; + GuidanceState = GuidanceState.Cruising; + + break; + } + + CheckIfTerminal(missileAltitude, targetPosition, upDirection); + + return _missile.vessel.CoM + (planarDirectionToTarget.normalized + upDirection.normalized) * 10f; + + case GuidanceState.Cruising: + + CheckIfTerminal(missileAltitude, targetPosition, upDirection); + //Altitude control + UpdatePitch(missileAltitude); + UpdateThrottle(); + + return _missile.vessel.CoM + 10 * planarDirectionToTarget.normalized + _pitchAngle * upDirection; + + case GuidanceState.Terminal: + + _missile.debugString.Append($"Descending"); + _missile.debugString.Append(Environment.NewLine); + + _missile.Throttle = Mathf.Clamp((float)(_missile.vessel.atmDensity * 10f), 0.01f, 1f); + + if (_missile is BDModularGuidance) + if (_missile.vessel.InVacuum()) + return _missile.vessel.CoM + _missile.vessel.Velocity() * 10; + + return MissileGuidance.GetAirToGroundTarget(targetPosition, _missile.vessel, 1.85f); + } + + return _missile.vessel.CoM + _missile.vessel.Velocity() * 10; + } + + private double CalculateFreeFallTime(double missileAltitude) + { + double vi = -_missile.vessel.verticalSpeed; + double a = 9.80665f; + double d = missileAltitude; + + double time1 = (-vi + Math.Sqrt(Math.Pow(vi, 2) - 4 * (0.5f * a) * (-d))) / a; + double time2 = (-vi - Math.Sqrt(Math.Pow(vi, 2) - 4 * (0.5f * a) * (-d))) / a; + + return Math.Max(time1, time2); + } + + private float GetProperDescentRatio(double missileAltitude) + { + float altitudePercentage = Mathf.Clamp01((float)(missileAltitude / 1000f)); + + return Mathf.Lerp(-1f, 1.85f, altitudePercentage); + } + + private void GetTelemetryData() + { + _lastDataRead = Time.time; + + _verticalAcceleration = (_missile.vessel.verticalSpeed - _lastVerticalSpeed); + _lastVerticalSpeed = _missile.vessel.verticalSpeed; + + _horizontalAcceleration = (_missile.vessel.horizontalSrfSpeed - _lastHorizontalSpeed); + _lastHorizontalSpeed = _missile.vessel.horizontalSrfSpeed; + } + + private bool CheckIfTerminal(double altitude, Vector3 targetPosition, Vector3 upDirection) + { + Vector3 surfacePos = this._missile.vessel.transform.position + + Vector3.Project(targetPosition - this._missile.vessel.transform.position, -upDirection); + + float distanceToTarget = Vector3.Distance(surfacePos, targetPosition); + + _missile.debugString.Append($"Distance to target" + distanceToTarget); + _missile.debugString.Append(Environment.NewLine); + double freefallTime = CalculateFreeFallTime(altitude); + + _missile.debugString.Append($"freefallTime" + freefallTime); + _missile.debugString.Append(Environment.NewLine); + + if (distanceToTarget < (freefallTime * _missile.vessel.horizontalSrfSpeed)) + { + GuidanceState = GuidanceState.Terminal; + return true; + } + return false; + } + + private void UpdateThrottle() + { + MakeDecisionAboutThrottle(_missile); + } + + private void UpdatePitch(double missileAltitude) + { + MakeDecisionAboutPitch(_missile, missileAltitude); + } + + private double GetCurrentAltitude(Vessel missileVessel) + { + var currentRadarAlt = MissileGuidance.GetRadarAltitude(missileVessel); + return currentRadarAlt; + } + + private double GetCurrentAltitudeAtPosition(Vector3 position) + { + var currentRadarAlt = MissileGuidance.GetRadarAltitudeAtPos(position); + + return currentRadarAlt; + } + + //private static double CalculateAltitude(Vector3 position, Vector3 upDirection, float currentRadarAlt, Vector3 tRayDirection) + //{ + // var terrainRay = new Ray(position, tRayDirection); + // RaycastHit rayHit; + + // if (Physics.Raycast(terrainRay, out rayHit, 30000, (1 << 15) | (1 << 17))) + // { + // var detectedAlt = + // Vector3.Project(rayHit.point - position, upDirection).magnitude; + + // return Mathf.Min(detectedAlt, currentRadarAlt); + // } + // return currentRadarAlt; + //} + + private bool CalculateFutureCollision(float predictionTime) + { + var terrainRay = new Ray(this._missile.vessel.CoM, this._missile.vessel.Velocity()); + RaycastHit hit; + return Physics.Raycast(terrainRay, out hit, (float)(this._missile.vessel.srfSpeed * predictionTime), (1 << 15) | (1 << 17)); + } + + private void MakeDecisionAboutThrottle(MissileBase missile) + { + const double maxError = 10; + _futureSpeed = CalculateFutureSpeed(); + + var currentSpeedDelta = missile.vessel.horizontalSrfSpeed - _missile.CruiseSpeed; + + if (_futureSpeed > missile.CruiseSpeed) + ThrottleDecision = ThrottleDecision.Decrease; + else if (Math.Abs(_futureSpeed - _missile.CruiseSpeed) < maxError) + ThrottleDecision = ThrottleDecision.Hold; + else + ThrottleDecision = ThrottleDecision.Increase; + + switch (ThrottleDecision) + { + case ThrottleDecision.Increase: + missile.Throttle = Mathf.Clamp(missile.Throttle + 0.001f, 0, 1f); + break; + + case ThrottleDecision.Decrease: + missile.Throttle = Mathf.Clamp(missile.Throttle - 0.001f, 0, 1f); + break; + + case ThrottleDecision.Hold: + break; + } + + _lastSpeedDelta = currentSpeedDelta; + } + + private void MakeDecisionAboutPitch(MissileBase missile, double missileAltitude) + { + _futureAltitude = CalculateFutureAltitude(_missile.CruisePredictionTime); + + PitchDecision futureDecision; + + if (this.GuidanceState != GuidanceState.Terminal && + (missileAltitude < 4d || CalculateFutureAltitude(1f) < 4d)) + { + futureDecision = PitchDecision.EmergencyAscent; + } + else if (this.GuidanceState != GuidanceState.Terminal && CalculateFutureCollision(_missile.CruisePredictionTime)) + { + futureDecision = PitchDecision.EmergencyAscent; + } + else if (_futureAltitude < missile.CruiseAltitude || missileAltitude < missile.CruiseAltitude) + { + futureDecision = PitchDecision.Ascent; + } + else if (_futureAltitude > missile.CruiseAltitude || missileAltitude > missile.CruiseAltitude) + { + futureDecision = PitchDecision.Descent; + } + else + { + futureDecision = PitchDecision.Hold; + } + + switch (futureDecision) + { + case PitchDecision.EmergencyAscent: + if (PitchDecision == futureDecision) + { + _pitchAngle = Mathf.Clamp(_pitchAngle + 1f, 1.5f, 100f); + } + else + { + _pitchAngle = 1.5f; + } + break; + + case PitchDecision.Ascent: + _pitchAngle = Mathf.Clamp(_pitchAngle + 0.0055f, -1.5f, 1.5f); + break; + + case PitchDecision.Descent: + _pitchAngle = Mathf.Clamp(_pitchAngle - 0.0025f, -1.5f, 1.5f); + break; + + case PitchDecision.Hold: + break; + } + + PitchDecision = futureDecision; + } + + private double CalculateFutureAltitude(float predictionTime) + { + Vector3 futurePosition = _missile.vessel.CoM + _missile.vessel.Velocity() * predictionTime + + 0.5f * _missile.vessel.acceleration_immediate * Math.Pow(predictionTime, 2); + + return GetCurrentAltitudeAtPosition(futurePosition); + } + + private double CalculateFutureSpeed() + { + return _missile.vessel.horizontalSrfSpeed + (_horizontalAcceleration / Time.fixedDeltaTime) * _missile.CruisePredictionTime; + } + + private bool MissileWillReachAltitude(double currentAltitude) + { + return _missile.vessel.orbit.ApA > _missile.CruiseAltitude; + } + } +} diff --git a/BDArmory/Guidances/IGuidance.cs b/BDArmory/Guidances/IGuidance.cs new file mode 100644 index 000000000..be7a16c90 --- /dev/null +++ b/BDArmory/Guidances/IGuidance.cs @@ -0,0 +1,10 @@ +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Guidances +{ + public interface IGuidance + { + Vector3 GetDirection(MissileBase missile, Vector3 targetPosition); + } +} \ No newline at end of file diff --git a/BDArmory/Guidances/MissileGuidance.cs b/BDArmory/Guidances/MissileGuidance.cs new file mode 100644 index 000000000..45a0d7813 --- /dev/null +++ b/BDArmory/Guidances/MissileGuidance.cs @@ -0,0 +1,487 @@ +using System; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Misc; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Guidances +{ + public class MissileGuidance + { + public static Vector3 GetAirToGroundTarget(Vector3 targetPosition, Vessel missileVessel, float descentRatio) + { + Vector3 upDirection = VectorUtils.GetUpDirection(missileVessel.CoM); + //-FlightGlobals.getGeeForceAtPosition(targetPosition).normalized; + Vector3 surfacePos = missileVessel.transform.position + + Vector3.Project(targetPosition - missileVessel.transform.position, upDirection); + //((float)missileVessel.altitude*upDirection); + Vector3 targetSurfacePos; + + targetSurfacePos = targetPosition; + + float distanceToTarget = Vector3.Distance(surfacePos, targetSurfacePos); + + if (missileVessel.srfSpeed < 75 && missileVessel.verticalSpeed < 10) + //gain altitude if launching from stationary + { + return missileVessel.transform.position + (5 * missileVessel.transform.forward) + (1 * upDirection); + } + + float altitudeClamp = Mathf.Clamp( + (distanceToTarget - ((float)missileVessel.srfSpeed * descentRatio)) * 0.22f, 0, + (float)missileVessel.altitude); + + //Debug.Log("AGM altitudeClamp =" + altitudeClamp); + + Vector3 finalTarget = targetPosition + (altitudeClamp * upDirection.normalized); + + //Debug.Log("Using agm trajectory. " + Time.time); + + return finalTarget; + } + + public static bool GetBallisticGuidanceTarget(Vector3 targetPosition, Vessel missileVessel, bool direct, + out Vector3 finalTarget) + { + Vector3 up = VectorUtils.GetUpDirection(missileVessel.transform.position); + Vector3 forward = Vector3.ProjectOnPlane(targetPosition - missileVessel.transform.position, up); + float speed = (float)missileVessel.srfSpeed; + float sqrSpeed = speed * speed; + float sqrSpeedSqr = sqrSpeed * sqrSpeed; + float g = (float)FlightGlobals.getGeeForceAtPosition(missileVessel.transform.position).magnitude; + float height = FlightGlobals.getAltitudeAtPos(targetPosition) - + FlightGlobals.getAltitudeAtPos(missileVessel.transform.position); + float sqrRange = forward.sqrMagnitude; + float range = Mathf.Sqrt(sqrRange); + + float plusOrMinus = direct ? -1 : 1; + + float top = sqrSpeed + (plusOrMinus * Mathf.Sqrt(sqrSpeedSqr - (g * ((g * sqrRange + (2 * height * sqrSpeed)))))); + float bottom = g * range; + float theta = Mathf.Atan(top / bottom); + + if (!float.IsNaN(theta)) + { + Vector3 finalVector = Quaternion.AngleAxis(theta * Mathf.Rad2Deg, Vector3.Cross(forward, up)) * forward; + finalTarget = missileVessel.transform.position + (100 * finalVector); + return true; + } + else + { + finalTarget = Vector3.zero; + return false; + } + } + + public static bool GetBallisticGuidanceTarget(Vector3 targetPosition, Vector3 missilePosition, + float missileSpeed, bool direct, out Vector3 finalTarget) + { + Vector3 up = VectorUtils.GetUpDirection(missilePosition); + Vector3 forward = Vector3.ProjectOnPlane(targetPosition - missilePosition, up); + float speed = missileSpeed; + float sqrSpeed = speed * speed; + float sqrSpeedSqr = sqrSpeed * sqrSpeed; + float g = (float)FlightGlobals.getGeeForceAtPosition(missilePosition).magnitude; + float height = FlightGlobals.getAltitudeAtPos(targetPosition) - + FlightGlobals.getAltitudeAtPos(missilePosition); + float sqrRange = forward.sqrMagnitude; + float range = Mathf.Sqrt(sqrRange); + + float plusOrMinus = direct ? -1 : 1; + + float top = sqrSpeed + (plusOrMinus * Mathf.Sqrt(sqrSpeedSqr - (g * ((g * sqrRange + (2 * height * sqrSpeed)))))); + float bottom = g * range; + float theta = Mathf.Atan(top / bottom); + + if (!float.IsNaN(theta)) + { + Vector3 finalVector = Quaternion.AngleAxis(theta * Mathf.Rad2Deg, Vector3.Cross(forward, up)) * forward; + finalTarget = missilePosition + (100 * finalVector); + return true; + } + else + { + finalTarget = Vector3.zero; + return false; + } + } + + public static Vector3 GetBeamRideTarget(Ray beam, Vector3 currentPosition, Vector3 currentVelocity, + float correctionFactor, float correctionDamping, Ray previousBeam) + { + float onBeamDistance = Vector3.Project(currentPosition - beam.origin, beam.direction).magnitude; + //Vector3 onBeamPos = beam.origin+Vector3.Project(currentPosition-beam.origin, beam.direction);//beam.GetPoint(Vector3.Distance(Vector3.Project(currentPosition-beam.origin, beam.direction), Vector3.zero)); + Vector3 onBeamPos = beam.GetPoint(onBeamDistance); + Vector3 previousBeamPos = previousBeam.GetPoint(onBeamDistance); + Vector3 beamVel = (onBeamPos - previousBeamPos) / Time.fixedDeltaTime; + Vector3 target = onBeamPos + (500f * beam.direction); + Vector3 offset = onBeamPos - currentPosition; + offset += beamVel * 0.5f; + target += correctionFactor * offset; + + Vector3 velDamp = correctionDamping * Vector3.ProjectOnPlane(currentVelocity - beamVel, beam.direction); + target -= velDamp; + + return target; + } + + public static Vector3 GetAirToAirTarget(Vector3 targetPosition, Vector3 targetVelocity, + Vector3 targetAcceleration, Vessel missileVessel, out float timeToImpact, float minSpeed = 200) + { + float leadTime = 0; + float targetDistance = Vector3.Distance(targetPosition, missileVessel.transform.position); + + Vector3 currVel = Mathf.Max((float)missileVessel.srfSpeed, minSpeed) * missileVessel.Velocity().normalized; + + leadTime = (float)(1 / ((targetVelocity - currVel).magnitude / targetDistance)); + timeToImpact = leadTime; + leadTime = Mathf.Clamp(leadTime, 0f, 8f); + + return targetPosition + (targetVelocity * leadTime); + } + + public static Vector3 GetAirToAirTargetModular(Vector3 targetPosition, Vector3 targetVelocity, Vector3 targetAcceleration, Vessel missileVessel, out float timeToImpact) + { + float targetDistance = Vector3.Distance(targetPosition, missileVessel.CoM); + + float leadTime = 0; + + //Basic lead time calculation + Vector3 currVel = ((float)missileVessel.srfSpeed * missileVessel.Velocity().normalized); + timeToImpact = (float)(1 / ((targetVelocity - currVel).magnitude / targetDistance)); + leadTime = Mathf.Clamp(timeToImpact, 0f, 8f); + + if (timeToImpact < 1) + { + float accuTimeToImpact = 0; + if (CalculateAccurateTimeToImpact(targetDistance, targetVelocity, missileVessel, + missileVessel.acceleration_immediate, targetAcceleration, out accuTimeToImpact)) + { + timeToImpact = accuTimeToImpact; + return targetPosition + (targetVelocity * accuTimeToImpact) + + targetAcceleration * 0.5f * Mathf.Pow(accuTimeToImpact, 2); + } + + return targetPosition + (targetVelocity * leadTime); + } + if (timeToImpact < 10) + { + return targetPosition + (targetVelocity * leadTime); + } + + return targetPosition; + } + + /// + /// Calculate a very accurate time to impact, use the out timeToimpact property if the method returned true + /// + /// + /// + /// + /// + /// + /// + /// true if it was possible to reach the target, false otherwise + private static bool CalculateAccurateTimeToImpact(float targetDistance, Vector3 targetVelocity, Vessel missileVessel, + Vector3d effectiveMissileAcceleration, Vector3 effectiveTargetAcceleration, out float timeToImpact) + { + int iterations = 0; + Vector3d relativeAcceleration = effectiveMissileAcceleration - effectiveTargetAcceleration; + Vector3d relativeVelocity = (float)missileVessel.srfSpeed * missileVessel.Velocity().normalized - + targetVelocity; + Vector3 missileFinalPosition = missileVessel.CoM; + float previousDistanceSqr = 0f; + float currentDistanceSqr; + do + { + missileFinalPosition += relativeVelocity * Time.fixedDeltaTime; + relativeVelocity += relativeAcceleration; + currentDistanceSqr = (missileFinalPosition - missileVessel.CoM).sqrMagnitude; + + if (currentDistanceSqr <= previousDistanceSqr) + { + Debug.Log("[BDArmory]: Accurate time to impact failed"); + + timeToImpact = 0; + return false; + } + + previousDistanceSqr = currentDistanceSqr; + iterations++; + } while (currentDistanceSqr < targetDistance * targetDistance); + + timeToImpact = Time.fixedDeltaTime * iterations; + return true; + } + + public static Vector3 GetAirToAirFireSolution(MissileBase missile, Vessel targetVessel) + { + if (!targetVessel) + { + return missile.transform.position + (missile.GetForwardTransform() * 1000); + } + Vector3 targetPosition = targetVessel.transform.position; + float leadTime = 0; + float targetDistance = Vector3.Distance(targetVessel.transform.position, missile.transform.position); + + Vector3 simMissileVel = 500 * (targetPosition - missile.transform.position).normalized; + + MissileLauncher launcher = missile as MissileLauncher; + float optSpeed = 400; //TODO: Add parameter + if (launcher != null) + { + optSpeed = launcher.optimumAirspeed; + } + simMissileVel = optSpeed * (targetPosition - missile.transform.position).normalized; + + leadTime = targetDistance / (float)(targetVessel.Velocity() - simMissileVel).magnitude; + leadTime = Mathf.Clamp(leadTime, 0f, 8f); + targetPosition = targetPosition + (targetVessel.Velocity() * leadTime); + + if (targetVessel && targetDistance < 800) + { + targetPosition += (Vector3)targetVessel.acceleration * 0.05f * leadTime * leadTime; + } + + return targetPosition; + } + + public static Vector3 GetAirToAirFireSolution(MissileBase missile, Vector3 targetPosition, Vector3 targetVelocity) + { + float leadTime = 0; + float targetDistance = Vector3.Distance(targetPosition, missile.transform.position); + + float optSpeed = 400; //TODO: Add parameter + MissileLauncher launcher = missile as MissileLauncher; + if (launcher != null) + { + optSpeed = launcher.optimumAirspeed; + } + + Vector3 simMissileVel = optSpeed * (targetPosition - missile.transform.position).normalized; + leadTime = targetDistance / (targetVelocity - simMissileVel).magnitude; + leadTime = Mathf.Clamp(leadTime, 0f, 8f); + + targetPosition = targetPosition + (targetVelocity * leadTime); + + return targetPosition; + } + + public static Vector3 GetCruiseTarget(Vector3 targetPosition, Vessel missileVessel, float radarAlt) + { + Vector3 upDirection = VectorUtils.GetUpDirection(missileVessel.transform.position); + float currentRadarAlt = GetRadarAltitude(missileVessel); + float distanceSqr = + (targetPosition - (missileVessel.transform.position - (currentRadarAlt * upDirection))).sqrMagnitude; + + Vector3 planarDirectionToTarget = + Vector3.ProjectOnPlane(targetPosition - missileVessel.transform.position, upDirection).normalized; + + float error; + + if (currentRadarAlt > 1600) + { + error = 500000; + } + else + { + Vector3 tRayDirection = (planarDirectionToTarget * 10) - (10 * upDirection); + Ray terrainRay = new Ray(missileVessel.transform.position, tRayDirection); + RaycastHit rayHit; + + if (Physics.Raycast(terrainRay, out rayHit, 8000, (1 << 15) | (1 << 17))) + { + float detectedAlt = + Vector3.Project(rayHit.point - missileVessel.transform.position, upDirection).magnitude; + + error = Mathf.Min(detectedAlt, currentRadarAlt) - radarAlt; + } + else + { + error = currentRadarAlt - radarAlt; + } + } + + error = Mathf.Clamp(0.05f * error, -5, 3); + return missileVessel.transform.position + (10 * planarDirectionToTarget) - (error * upDirection); + } + + public static Vector3 GetTerminalManeuveringTarget(Vector3 targetPosition, Vessel missileVessel, float radarAlt) + { + Vector3 upDirection = -FlightGlobals.getGeeForceAtPosition(missileVessel.GetWorldPos3D()).normalized; + Vector3 planarVectorToTarget = Vector3.ProjectOnPlane(targetPosition - missileVessel.transform.position, + upDirection); + Vector3 planarDirectionToTarget = planarVectorToTarget.normalized; + Vector3 crossAxis = Vector3.Cross(planarDirectionToTarget, upDirection).normalized; + float sinAmplitude = Mathf.Clamp(Vector3.Distance(targetPosition, missileVessel.transform.position) - 850, 0, + 4500); + Vector3 sinOffset = (Mathf.Sin(1.25f * Time.time) * sinAmplitude * crossAxis); + Vector3 targetSin = targetPosition + sinOffset; + Vector3 planarSin = missileVessel.transform.position + planarVectorToTarget + sinOffset; + + Vector3 finalTarget; + float finalDistance = 2500 + GetRadarAltitude(missileVessel); + if ((targetPosition - missileVessel.transform.position).sqrMagnitude > finalDistance * finalDistance) + { + finalTarget = targetPosition; + } + else if (!GetBallisticGuidanceTarget(targetSin, missileVessel, true, out finalTarget)) + { + //finalTarget = GetAirToGroundTarget(targetSin, missileVessel, 6); + finalTarget = planarSin; + } + return finalTarget; + } + + public static FloatCurve DefaultLiftCurve = null; + public static FloatCurve DefaultDragCurve = null; + + public static Vector3 DoAeroForces(MissileLauncher ml, Vector3 targetPosition, float liftArea, float steerMult, + Vector3 previousTorque, float maxTorque, float maxAoA) + { + if (DefaultLiftCurve == null) + { + DefaultLiftCurve = new FloatCurve(); + DefaultLiftCurve.Add(0, 0); + DefaultLiftCurve.Add(8, .35f); + // DefaultLiftCurve.Add(19, 1); + // DefaultLiftCurve.Add(23, .9f); + DefaultLiftCurve.Add(30, 1.5f); + DefaultLiftCurve.Add(65, .6f); + DefaultLiftCurve.Add(90, .7f); + } + + if (DefaultDragCurve == null) + { + DefaultDragCurve = new FloatCurve(); + DefaultDragCurve.Add(0, 0.00215f); + DefaultDragCurve.Add(5, .00285f); + DefaultDragCurve.Add(15, .007f); + DefaultDragCurve.Add(29, .01f); + DefaultDragCurve.Add(55, .3f); + DefaultDragCurve.Add(90, .5f); + } + + FloatCurve liftCurve = DefaultLiftCurve; + FloatCurve dragCurve = DefaultDragCurve; + + return DoAeroForces(ml, targetPosition, liftArea, steerMult, previousTorque, maxTorque, maxAoA, liftCurve, + dragCurve); + } + + public static Vector3 DoAeroForces(MissileLauncher ml, Vector3 targetPosition, float liftArea, float steerMult, + Vector3 previousTorque, float maxTorque, float maxAoA, FloatCurve liftCurve, FloatCurve dragCurve) + { + Rigidbody rb = ml.part.rb; + double airDensity = ml.vessel.atmDensity; + double airSpeed = ml.vessel.srfSpeed; + Vector3d velocity = ml.vessel.Velocity(); + + //temp values + Vector3 CoL = new Vector3(0, 0, -1f); + float liftMultiplier = BDArmorySettings.GLOBAL_LIFT_MULTIPLIER; + float dragMultiplier = BDArmorySettings.GLOBAL_DRAG_MULTIPLIER; + + //lift + float AoA = Mathf.Clamp(Vector3.Angle(ml.transform.forward, velocity.normalized), 0, 90); + if (AoA > 0) + { + double liftForce = 0.5 * airDensity * Math.Pow(airSpeed, 2) * liftArea * liftMultiplier * liftCurve.Evaluate(AoA); + Vector3 forceDirection = Vector3.ProjectOnPlane(-velocity, ml.transform.forward).normalized; + rb.AddForceAtPosition((float)liftForce * forceDirection, + ml.transform.TransformPoint(ml.part.CoMOffset + CoL)); + } + + //drag + if (airSpeed > 0) + { + double dragForce = 0.5 * airDensity * Math.Pow(airSpeed, 2) * liftArea * dragMultiplier * dragCurve.Evaluate(AoA); + rb.AddForceAtPosition((float)dragForce * -velocity.normalized, + ml.transform.TransformPoint(ml.part.CoMOffset + CoL)); + } + + //guidance + if (airSpeed > 1 || (ml.vacuumSteerable && ml.Throttle > 0)) + { + Vector3 targetDirection; + float targetAngle; + if (AoA < maxAoA) + { + targetDirection = (targetPosition - ml.transform.position); + targetAngle = Vector3.Angle(velocity.normalized, targetDirection) * 4; + } + else + { + targetDirection = velocity.normalized; + targetAngle = AoA; + } + + Vector3 torqueDirection = -Vector3.Cross(targetDirection, velocity.normalized).normalized; + torqueDirection = ml.transform.InverseTransformDirection(torqueDirection); + + float torque = Mathf.Clamp(targetAngle * steerMult, 0, maxTorque); + Vector3 finalTorque = Vector3.ProjectOnPlane(Vector3.Lerp(previousTorque, torqueDirection * torque, 1), + Vector3.forward); + + rb.AddRelativeTorque(finalTorque); + return finalTorque; + } + else + { + Vector3 finalTorque = Vector3.ProjectOnPlane(Vector3.Lerp(previousTorque, Vector3.zero, 0.25f), + Vector3.forward); + rb.AddRelativeTorque(finalTorque); + return finalTorque; + } + } + + public static float GetRadarAltitude(Vessel vessel) + { + float radarAlt = Mathf.Clamp((float)(vessel.mainBody.GetAltitude(vessel.CoM) - vessel.terrainAltitude), 0, + (float)vessel.altitude); + return radarAlt; + } + + public static float GetRadarAltitudeAtPos(Vector3 position) + { + double latitudeAtPos = FlightGlobals.currentMainBody.GetLatitude(position); + double longitudeAtPos = FlightGlobals.currentMainBody.GetLongitude(position); + + float radarAlt = Mathf.Clamp( + (float)(FlightGlobals.currentMainBody.GetAltitude(position) - + FlightGlobals.currentMainBody.TerrainAltitude(latitudeAtPos, longitudeAtPos)), 0, + (float)FlightGlobals.currentMainBody.GetAltitude(position)); + return radarAlt; + } + + public static float GetRaycastRadarAltitude(Vector3 position) + { + Vector3 upDirection = -FlightGlobals.getGeeForceAtPosition(position).normalized; + + float altAtPos = FlightGlobals.getAltitudeAtPos(position); + if (altAtPos < 0) + { + position += 2 * Mathf.Abs(altAtPos) * upDirection; + } + + Ray ray = new Ray(position, -upDirection); + float rayDistance = FlightGlobals.getAltitudeAtPos(position); + + if (rayDistance < 0) + { + return 0; + } + + RaycastHit rayHit; + if (Physics.Raycast(ray, out rayHit, rayDistance, (1 << 15) | (1 << 17))) + { + return rayHit.distance; + } + else + { + return rayDistance; + } + } + } +} diff --git a/BDArmory/Misc/BDAEditorTools.cs b/BDArmory/Misc/BDAEditorTools.cs new file mode 100644 index 000000000..1f428e566 --- /dev/null +++ b/BDArmory/Misc/BDAEditorTools.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Misc +{ + [KSPAddon(KSPAddon.Startup.MainMenu, true)] + public class BDAEditorTools : MonoBehaviour + { + private static readonly List radars = new List(); + + public const string Manufacturer = "Bahamuto Dynamics"; + + void Awake() + { + radars.Clear(); + var availableParts = new List(); + var count = PartLoader.LoadedPartsList.Count; + for (int i = 0; i < count; ++i) + { + var avPart = PartLoader.LoadedPartsList[i]; + if (!avPart.partPrefab) continue; + if (avPart.manufacturer == Manufacturer) + { + availableParts.Add(avPart); + } + if (avPart.partPrefab.GetComponent() != null) + { + radars.Add(avPart); + } + } + + print(Manufacturer + " Filter Count: " + availableParts.Count); + if (availableParts.Count > 0) + GameEvents.onGUIEditorToolbarReady.Add(CheckDump); + } + + void CheckDump() + { + // dump parts to .CSV list + if (BDArmorySettings.DRAW_DEBUG_LABELS) + dumpParts(); + } + + public static List getRadars() + { + List results = new List(150); + + foreach (var item in radars) + { + var radar = item.partPrefab.GetComponent(); + if (radar != null && (radar.canScan || radar.canLock)) + results.Add(radar); + } + + return results; + } + + void dumpParts() + { + String gunName = "bda_weapons_list.csv"; + String missileName = "bda_missile_list.csv"; + String radarName = "bda_radar_list.csv"; + String jammerName = "bda_jammer_list.csv"; + ModuleWeapon weapon = null; + MissileLauncher missile = null; + ModuleRadar radar = null; + ModuleECMJammer jammer = null; + + // 1. create the file + var fileguns = KSP.IO.TextWriter.CreateForType(gunName); + var filemissiles = KSP.IO.TextWriter.CreateForType(missileName); + var fileradars = KSP.IO.TextWriter.CreateForType(radarName); + var filejammers = KSP.IO.TextWriter.CreateForType(jammerName); + + // 2. write header + fileguns.WriteLine("NAME;TITLE;AUTHOR;MANUFACTURER;PART_MASS;PART_COST;PART_CRASHTOLERANCE;PART_MAXTEMP;WEAPON_RPM;WEAPON_DEVIATION;WEAPON_MAXEFFECTIVEDISTANCE;WEAPON_TYPE;WEAPON_BULLETTYPE;WEAPON_AMMONAME;WEAPON_BULLETMASS;WEAPON_BULLET_VELOCITY;WEAPON_MAXHEAT;WEAPON_HEATPERSHOT;WEAPON_HEATLOSS;CANNON_SHELLPOWER;CANNON_SHELLHEAT;CANNON_SHELLRADIUS;CANNON_AIRDETONATION"); + filemissiles.WriteLine("NAME;TITLE;AUTHOR;MANUFACTURER;PART_MASS;PART_COST;PART_CRASHTOLERANCE;PART_MAXTEMP;" + + "MISSILE_THRUST;MISSILE_BOOSTTIME;MISSILE_CRUISETHRUST;MISSILE_CRUISETIME;MISSILE_MAXTURNRATEDPS;MISSILE_BLASTPOWER;MISSILE_BLASTHEAT;MISSILE_BLASTRADIUS;MISSILE_GUIDANCEACTIVE;MISSILE_HOMINGTYPE;MISSILE_TARGETINGTYPE;MISSILE_MINLAUNCHSPEED;MISSILE_MINSTATICLAUNCHRANGE;MISSILE_MAXSTATICLAUNCHRANGE;MISSILE_OPTIMUMAIRSPEED;" + + "CRUISE_TERMINALMANEUVERING; CRUISE_TERMINALGUIDANCETYPE; CRUISE_TERMINALGUIDANCEDISTANCE;" + + "RADAR_ACTIVERADARRANGE;RADAR_RADARLOAL;" + + "TRACK_MAXOFFBORESIGHT;TRACK_LOCKEDSENSORFOV;" + + "HEAT_HEATTHRESHOLD;" + + "LASER_BEAMCORRECTIONFACTOR; LASER_BEAMCORRECTIONDAMPING" + ); + fileradars.WriteLine("NAME;TITLE;AUTHOR;MANUFACTURER;PART_MASS;PART_COST;PART_CRASHTOLERANCE;PART_MAXTEMP;radar_name;rwrThreatType;omnidirectional;directionalFieldOfView;boresightFOV;" + + "scanRotationSpeed;lockRotationSpeed;lockRotationAngle;showDirectionWhileScan;multiLockFOV;lockAttemptFOV;canScan;canLock;canTrackWhileScan;canRecieveRadarData;" + + "maxLocks;radarGroundClutterFactor;radarDetectionCurve;radarLockTrackCurve" + ); + filejammers.WriteLine("NAME;TITLE;AUTHOR;MANUFACTURER;PART_MASS;PART_COST;PART_CRASHTOLERANCE;PART_MAXTEMP;alwaysOn;rcsReduction;rcsReducationFactor;lockbreaker;lockbreak_strength;jammerStrength"); + + Debug.Log("Dumping parts..."); + + // 3. iterate weapons and write out fields + foreach (var item in PartLoader.LoadedPartsList) + { + weapon = null; + missile = null; + radar = null; + jammer = null; + weapon = item.partPrefab.GetComponent(); + missile = item.partPrefab.GetComponent(); + radar = item.partPrefab.GetComponent(); + jammer = item.partPrefab.GetComponent(); + + if (weapon != null) + { + fileguns.WriteLine( + item.name + ";" + item.title + ";" + item.author + ";" + item.manufacturer + ";" + item.partPrefab.mass + ";" + item.cost + ";" + item.partPrefab.crashTolerance + ";" + item.partPrefab.maxTemp + ";" + + weapon.roundsPerMinute + ";" + weapon.maxDeviation + ";" + weapon.maxEffectiveDistance + ";" + weapon.weaponType + ";" + weapon.bulletType + ";" + weapon.ammoName + ";" + weapon.bulletMass + ";" + weapon.bulletVelocity + ";" + + weapon.maxHeat + ";" + weapon.heatPerShot + ";" + weapon.heatLoss + ";" + weapon.cannonShellPower + ";" + weapon.cannonShellHeat + ";" + weapon.cannonShellRadius + ";" + weapon.airDetonation + ); + } + + if (missile != null) + { + filemissiles.WriteLine( + item.name + ";" + item.title + ";" + item.author + ";" + item.manufacturer + ";" + item.partPrefab.mass + ";" + item.cost + ";" + item.partPrefab.crashTolerance + ";" + item.partPrefab.maxTemp + ";" + + missile.thrust + ";" + missile.boostTime + ";" + missile.cruiseThrust + ";" + missile.cruiseTime + ";" + missile.maxTurnRateDPS + ";" + missile.blastPower + ";" + missile.blastHeat + ";" + missile.blastRadius + ";" + missile.guidanceActive + ";" + missile.homingType + ";" + missile.targetingType + ";" + missile.minLaunchSpeed + ";" + missile.minStaticLaunchRange + ";" + missile.maxStaticLaunchRange + ";" + missile.optimumAirspeed + ";" + + missile.terminalManeuvering + ";" + missile.terminalGuidanceType + ";" + missile.terminalGuidanceDistance + ";" + + missile.activeRadarRange + ";" + missile.radarLOAL + ";" + + missile.maxOffBoresight + ";" + missile.lockedSensorFOV + ";" + + missile.heatThreshold + ";" + + missile.beamCorrectionFactor + ";" + missile.beamCorrectionDamping + ); + } + + if (radar != null) + { + fileradars.WriteLine( + item.name + ";" + item.title + ";" + item.author + ";" + item.manufacturer + ";" + item.partPrefab.mass + ";" + item.cost + ";" + item.partPrefab.crashTolerance + ";" + item.partPrefab.maxTemp + ";" + + radar.radarName + ";" + radar.getRWRType(radar.rwrThreatType) + ";" + radar.omnidirectional + ";" + radar.directionalFieldOfView + ";" + radar.boresightFOV + ";" + radar.scanRotationSpeed + ";" + radar.lockRotationSpeed + ";" + + radar.lockRotationAngle + ";" + radar.showDirectionWhileScan + ";" + radar.multiLockFOV + ";" + radar.lockAttemptFOV + ";" + + radar.canScan + ";" + radar.canLock + ";" + radar.canTrackWhileScan + ";" + radar.canRecieveRadarData + ";" + + radar.maxLocks + ";" + radar.radarGroundClutterFactor + ";" + + radar.radarDetectionCurve.Evaluate(radar.radarMaxDistanceDetect) + "@" + radar.radarMaxDistanceDetect + ";" + + radar.radarLockTrackCurve.Evaluate(radar.radarMaxDistanceLockTrack) + "@" + radar.radarMaxDistanceLockTrack + ); + } + + if (jammer != null) + { + filejammers.WriteLine( + item.name + ";" + item.title + ";" + item.author + ";" + item.manufacturer + ";" + item.partPrefab.mass + ";" + item.cost + ";" + item.partPrefab.crashTolerance + ";" + item.partPrefab.maxTemp + ";" + + jammer.alwaysOn + ";" + jammer.rcsReduction + ";" + jammer.rcsReductionFactor + ";" + jammer.lockBreaker + ";" + jammer.lockBreakerStrength + ";" + jammer.jammerStrength + ); + } + } + + // 4. close file + fileguns.Close(); + filemissiles.Close(); + fileradars.Close(); + filejammers.Close(); + Debug.Log("...dumping parts complete."); + } + } +} diff --git a/BahaTurret/BDAExtensions.cs b/BDArmory/Misc/BDAExtensions.cs similarity index 59% rename from BahaTurret/BDAExtensions.cs rename to BDArmory/Misc/BDAExtensions.cs index 19c84de71..01e0b5767 100644 --- a/BahaTurret/BDAExtensions.cs +++ b/BDArmory/Misc/BDAExtensions.cs @@ -1,17 +1,11 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; using System.Collections.Generic; using System.Linq; -using UnityEngine; -namespace BahaTurret +using BDArmory.CounterMeasure; +using BDArmory.Modules; +using BDArmory.Parts; +using BDArmory.Radar; + +namespace BDArmory.Misc { public static class BDAExtensions { @@ -21,7 +15,8 @@ public static IEnumerable BDAParts(this List parts { return (from avPart in parts.Where(p => p.partPrefab) let missile = avPart.partPrefab.GetComponent() - let moduleWeapon = avPart.partPrefab.GetComponent() + let mmissile = avPart.partPrefab.GetComponent() + let moduleWeapon = avPart.partPrefab.GetComponent() let missileFire = avPart.partPrefab.GetComponent() let moduleRadar = avPart.partPrefab.GetComponent() let cm = avPart.partPrefab.GetComponent() @@ -29,7 +24,7 @@ public static IEnumerable BDAParts(this List parts let rocket = avPart.partPrefab.GetComponent() let otherModule = avPart.partPrefab.GetComponent() where missile || moduleWeapon || missileFire || moduleRadar || cm || tgp || rocket || otherModule - select avPart).ToList(); + select avPart).AsEnumerable(); } } } diff --git a/BDArmory/Misc/BDAModuleInfos.cs b/BDArmory/Misc/BDAModuleInfos.cs new file mode 100644 index 000000000..91610ff28 --- /dev/null +++ b/BDArmory/Misc/BDAModuleInfos.cs @@ -0,0 +1,58 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace BDArmory.Misc +{ + /// + /// This class supports reloading the partModule info blocks when the editor loads. This allows us to obtain current data on the module configurations. + /// due to changes in the environment after part loading at game start. + /// + [KSPAddon(KSPAddon.Startup.EditorAny, false)] + internal class BDAModuleInfos : MonoBehaviour + { + public static Dictionary Modules = new Dictionary() + { + //{"WeaponModule", "Weapon"}, + { "BDModuleSurfaceAI", "BDModule Surface AI"} + }; + + public void Start() + { + StartCoroutine(ReloadModuleInfos()); + } + + internal static IEnumerator ReloadModuleInfos() + { + yield return null; + + IEnumerator loadedParts = PartLoader.LoadedPartsList.GetEnumerator(); + while (loadedParts.MoveNext()) + { + if (loadedParts.Current == null) continue; + foreach (string key in Modules.Keys) + { + if (!loadedParts.Current.partPrefab.Modules.Contains(key)) continue; + IEnumerator partModules = loadedParts.Current.partPrefab.Modules.GetEnumerator(); + while (partModules.MoveNext()) + { + if (partModules.Current == null) continue; + if (partModules.Current.moduleName != key) continue; + string info = partModules.Current.GetInfo(); + for (int y = 0; y < loadedParts.Current.moduleInfos.Count; y++) + { + Debug.Log($"moduleName: {loadedParts.Current.moduleInfos[y].moduleName}"); + Debug.Log($"KeyValue: {Modules[key]}"); + if (loadedParts.Current.moduleInfos[y].moduleName != Modules[key]) continue; + loadedParts.Current.moduleInfos[y].info = info; + break; + } + } + partModules.Dispose(); + } + } + + loadedParts.Dispose(); + } + } +} diff --git a/BDArmory/Misc/BDATooltips.cs b/BDArmory/Misc/BDATooltips.cs new file mode 100644 index 000000000..df535da30 --- /dev/null +++ b/BDArmory/Misc/BDATooltips.cs @@ -0,0 +1,17 @@ +using BDArmory.UI; + +namespace BDArmory.Misc +{ + public static class BDATooltips + { + public static string WM_RIPPLE + { + get + { + return + "The ripple function allows you to fire missiles, rockets, or bombs at the configured rate by holding down the main fire key (" + + BDInputSettingsFields.WEAP_FIRE_KEY.inputString + ")"; + } + } + } +} diff --git a/BDArmory/Misc/BDAcTools.cs b/BDArmory/Misc/BDAcTools.cs new file mode 100644 index 000000000..1e970e299 --- /dev/null +++ b/BDArmory/Misc/BDAcTools.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace BDArmory.Misc +{ + public static class BDAcTools + { + public static Vector3 WorldUp(Vessel vessel) + { + if (vessel != null) + return (vessel.GetComponent().position - vessel.mainBody.position).normalized; + else + return Vector3.zero; + } + + public static T Clamp(T value, T min, T max) + where T : System.IComparable + { + T result = value; + if (value.CompareTo(max) > 0) + result = max; + if (value.CompareTo(min) < 0) + result = min; + return result; + } + + public static double Clamp(double value, double min, double max) + { + double result = value; + if (value > max) + result = max; + if (value < min) + result = min; + return result; + } + + public static String AppPath = KSPUtil.ApplicationRootPath.Replace("\\", "/"); + public static String PlugInDataPath = AppPath + "GameData/BDAcCategorynFS/Plugin/"; + + public static FloatCurve stringToFloatCurve(string curveString) + { + FloatCurve resultCurve = new FloatCurve(); + + string[] keyString = curveString.Split(';'); + for (int i = 0; i < keyString.Length; i++) + { + string[] valueString = keyString[i].Split(','); + if (valueString.Length >= 2) + { + Vector4 key = Vector4.zero; + float.TryParse(valueString[0], out key.x); + float.TryParse(valueString[1], out key.y); + if (valueString.Length == 4) + { + float.TryParse(valueString[2], out key.z); + float.TryParse(valueString[3], out key.w); + } + + resultCurve.Add(key.x, key.y, key.z, key.w); + } + } + return resultCurve; + } + + public static List parseIntegers(string stringOfInts) + { + List newIntList = new List(); + string[] valueArray = stringOfInts.Split(';'); + for (int i = 0; i < valueArray.Length; i++) + { + int newValue = 0; + if (int.TryParse(valueArray[i], out newValue)) + { + newIntList.Add(newValue); + } + else + { + Debug.Log("invalid integer: " + valueArray[i]); + } + } + return newIntList; + } + + public static List parseFloats(string stringOfFloats) + { + System.Collections.Generic.List list = new System.Collections.Generic.List(); + string[] array = stringOfFloats.Split(';'); + for (int i = 0; i < array.Length; i++) + { + float item = 0f; + if (float.TryParse(array[i].Trim(), out item)) + { + list.Add(item); + } + else + { + Debug.Log("invalid float: " + array[i]); + } + } + return list; + } + + public static List ParseDoubles(string stringOfDoubles) + { + System.Collections.Generic.List list = new System.Collections.Generic.List(); + string[] array = stringOfDoubles.Trim().Split(';'); + for (int i = 0; i < array.Length; i++) + { + double item = 0f; + if (double.TryParse(array[i].Trim(), out item)) + { + list.Add(item); + } + else + { + Debug.Log("FSBDAcTools: invalid float: [len:" + array[i].Length + "] '" + array[i] + "']"); + } + } + return list; + } + + public static List ParseNames(string names) + { + return ParseNames(names, false, true, string.Empty); + } + + public static List ParseNames(string names, bool replaceBackslashErrors) + { + return ParseNames(names, replaceBackslashErrors, true, string.Empty); + } + + public static List ParseNames(string names, bool replaceBackslashErrors, bool trimWhiteSpace, string prefix) + { + List source = names.Split(';').ToList(); + for (int i = source.Count - 1; i >= 0; i--) + { + if (source[i] == string.Empty) + { + source.RemoveAt(i); + } + } + if (trimWhiteSpace) + { + for (int i = 0; i < source.Count; i++) + { + source[i] = source[i].Trim(' '); + } + } + if (prefix != string.Empty) + { + for (int i = 0; i < source.Count; i++) + { + source[i] = prefix + source[i]; + } + } + if (replaceBackslashErrors) + { + for (int i = 0; i < source.Count; i++) + { + source[i] = source[i].Replace('\\', '/'); + } + } + return source.ToList(); + } + + #region refresh tweakable GUI + + // Code from https://github.com/Swamp-Ig/KSPAPIExtensions/blob/master/Source/Utils/KSPUtils.cs#L62 + + private static FieldInfo windowListField; + + /// + /// Find the UIPartActionWindow for a part. Usually this is useful just to mark it as dirty. + /// + public static UIPartActionWindow FindActionWindow(this Part part) + { + if (part == null) + return null; + + // We need to do quite a bit of piss-farting about with reflection to + // dig the thing out. We could just use Object.Find, but that requires hitting a heap more objects. + UIPartActionController controller = UIPartActionController.Instance; + if (controller == null) + return null; + + if (windowListField == null) + { + Type cntrType = typeof(UIPartActionController); + foreach (FieldInfo info in cntrType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) + { + if (info.FieldType == typeof(List)) + { + windowListField = info; + goto foundField; + } + } + Debug.LogWarning("*PartUtils* Unable to find UIPartActionWindow list"); + return null; + } + foundField: + + List uiPartActionWindows = (List)windowListField.GetValue(controller); + if (uiPartActionWindows == null) + return null; + + return uiPartActionWindows.FirstOrDefault(window => window != null && window.part == part); + } + + #endregion refresh tweakable GUI + } + + public class MouseEventHandler : MonoBehaviour + { + public delegate void GenericDelegate(); + + public GenericDelegate mouseDownEvent; + + public void OnMouseDown() + { + mouseDownEvent(); + } + } + + public struct IntVector2 + { + public int x; + public int y; + + public IntVector2(int _x, int _y) + { + x = _x; + y = _y; + } + + public IntVector2(float _x, float _y) + { + x = (int)_x; + y = (int)_y; + } + + public Vector2 toVector2() + { + return new Vector2((float)x, (float)y); + } + + public float magnitude() + { + return new Vector2((float)x, (float)y).magnitude; + } + + public override string ToString() + { + return ("(" + x + ", " + y + ")"); + } + } +} diff --git a/BDArmory/Misc/BDTeam.cs b/BDArmory/Misc/BDTeam.cs new file mode 100644 index 000000000..c22d33353 --- /dev/null +++ b/BDArmory/Misc/BDTeam.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using BDArmory.UI; + +namespace BDArmory.Misc +{ + [Serializable] + public class BDTeam + { + // No warranty is provided for changing the Name, but this makes serialization easier. :) + public string Name; + + public bool Neutral; + + public List Allies = new List(); + + public BDTeam(string name, List allies = null, bool neutral = false) + { + Name = name; + Neutral = neutral; + Allies = allies ?? new List(); + } + + public static BDTeam Get(string name) + { + if (!BDArmorySetup.Instance.Teams.ContainsKey(name)) + BDArmorySetup.Instance.Teams.Add(name, new BDTeam(name)); + return BDArmorySetup.Instance.Teams[name]; + } + + public bool IsEnemy(BDTeam other) + { + if (Neutral || other == null || other.Neutral || other.Name == Name || Allies.Contains(other.Name)) + return false; + return true; + } + + public bool IsFriendly(BDTeam other) + { + if (other == null) + return false; + return !IsEnemy(other); + } + + public override string ToString() => Name; + + public static BDTeam Deserialize(string teamString) + { + // Backward compatibility + if (string.IsNullOrEmpty(teamString) || teamString == "False") + return BDTeam.Get("A"); + else if (teamString == "True") + return BDTeam.Get("B"); + try + { + BDTeam team = UnityEngine.JsonUtility.FromJson(Misc.JsonDecompat(teamString)); + if (!BDArmorySetup.Instance.Teams.ContainsKey(team.Name)) + { + BDArmorySetup.Instance.Teams.Add(team.Name, team); + } + return BDArmorySetup.Instance.Teams[team.Name]; + } + catch + { + return BDTeam.Get("A"); + } + } + + public string Serialize() + { + return Misc.JsonCompat(UnityEngine.JsonUtility.ToJson(this)); + } + + public override int GetHashCode() => Name.GetHashCode(); + + public bool Equals(BDTeam other) => Name == other?.Name; + + public override bool Equals(object obj) => Equals(obj as BDTeam); + + public static bool operator ==(BDTeam left, BDTeam right) => Equals(left, right); + + public static bool operator !=(BDTeam left, BDTeam right) => !Equals(left, right); + } +} diff --git a/BahaTurret/BahaTurretBullet.cs b/BDArmory/Misc/BahaTurretBullet.cs similarity index 54% rename from BahaTurret/BahaTurretBullet.cs rename to BDArmory/Misc/BahaTurretBullet.cs index 537f8508f..e75f59981 100644 --- a/BahaTurret/BahaTurretBullet.cs +++ b/BDArmory/Misc/BahaTurretBullet.cs @@ -1,7 +1,5 @@ -using System; -using UnityEngine; - -namespace BahaTurret +/* +namespace BDArmory.Misc { /// /// DEPRECATED @@ -16,29 +14,28 @@ public enum BulletTypes{Standard, Explosive} public Vessel sourceVessel; public Color lightColor = Misc.ParseColor255("255, 235, 145, 255"); public Color projectileColor; - + public string bulletTexturePath; - + public bool fadeColor; public Color startColor; Color currentColor; - + public bool bulletDrop = true; - + public float tracerStartWidth = 1; public float tracerEndWidth = 1; public float tracerLength = 0; - + public float initialSpeed; - - + public Vector3 prevPosition; public Vector3 currPosition; //explosive parameters public float radius = 30; public float blastPower = 8; - + public string explModelPath; public string explSoundPath; // @@ -50,43 +47,41 @@ public enum BulletTypes{Standard, Explosive} LineRenderer bulletTrail; // VectorLine bulletVectorLine; //Material lineMat; - - + Vector3 sourceOriginalV; - bool hasBounced = false; - + bool hasBounced; + float maxDistance; //bool isUnderwater = false; Rigidbody rb; - + void Start() { startPosition = transform.position; - float maxLimit = Mathf.Clamp(BDArmorySettings.MAX_BULLET_RANGE, 0, 8000); - maxDistance = Mathf.Clamp(BDArmorySettings.PHYSICS_RANGE, 2500, maxLimit); + float maxLimit = Mathf.Clamp(BDArmorySetup.MAX_BULLET_RANGE, 0, 8000); + maxDistance = Mathf.Clamp(BDArmorySetup.PHYSICS_RANGE, 2500, maxLimit); projectileColor.a = projectileColor.a/2; startColor.a = startColor.a/2; - + currentColor = projectileColor; - if(fadeColor) + if(fadeColor) { currentColor = startColor; } startTime = Time.time; prevPosition = gameObject.transform.position; - - sourceOriginalV = sourceVessel.rb_velocity; - + + sourceOriginalV = sourceVessel.Velocity(); + Light light = gameObject.AddComponent(); light.type = LightType.Point; light.color = lightColor; light.range = 8; light.intensity = 1; - - + bulletTrail = gameObject.AddComponent(); bulletTrail.SetVertexCount(2); bulletTrail.SetPosition(0, transform.position); @@ -96,15 +91,11 @@ void Start() bulletTrail.material = new Material(Shader.Find("KSP/Particles/Alpha Blended")); bulletTrail.material.mainTexture = GameDatabase.Instance.GetTexture(bulletTexturePath, false); bulletTrail.material.SetColor("_TintColor", currentColor); - - + rb = GetComponent (); rb.useGravity = false; - - - } - + void FixedUpdate() { float distanceFromStart = Vector3.Distance(transform.position, startPosition); @@ -113,61 +104,148 @@ void FixedUpdate() { rb.velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * TimeWarp.fixedDeltaTime; } - - + if(tracerLength == 0) { - bulletTrail.SetPosition(0, transform.position+(rb.velocity * TimeWarp.fixedDeltaTime)-(FlightGlobals.ActiveVessel.rb_velocity*TimeWarp.fixedDeltaTime)); + bulletTrail.SetPosition(0, transform.position+(rb.velocity * TimeWarp.fixedDeltaTime)-(FlightGlobals.ActiveVessel.Velocity()*TimeWarp.fixedDeltaTime)); } else { - bulletTrail.SetPosition(0, transform.position + ((rb.velocity-sourceOriginalV).normalized * tracerLength)); + bulletTrail.SetPosition(0, transform.position + ((rb.velocity-sourceOriginalV).normalized * tracerLength)); } if(fadeColor) { FadeColor(); bulletTrail.material.SetColor("_TintColor", currentColor); } - + float fov = FlightCamera.fetch.mainCamera.fieldOfView; float width1 = (fov/60) * tracerStartWidth * Mathf.Clamp(Vector3.Distance(transform.position, FlightCamera.fetch.mainCamera.transform.position),0,3000)/50; float width2 = (fov/60) * tracerEndWidth * Mathf.Clamp(Vector3.Distance(transform.position, FlightCamera.fetch.mainCamera.transform.position),0,3000)/50; - + bulletTrail.SetWidth(width1, width2); - + bulletTrail.SetPosition(1, transform.position); - - - + currPosition = gameObject.transform.position; - + if(distanceFromStart > maxDistance) { - GameObject.Destroy(gameObject); + Destroy(gameObject); return; } - + if(Time.time - startTime > 0.01f) { - light.intensity = 0; + Light light = gameObject.GetComponent(); + light.intensity = 0; float dist = initialSpeed*TimeWarp.fixedDeltaTime; - + Ray ray = new Ray(prevPosition, currPosition-prevPosition); RaycastHit hit; - if(Physics.Raycast(ray, out hit, dist, 557057)) + //KerbalEVA hitEVA = null; + //if (Physics.Raycast(ray, out hit, dist, 2228224)) + //{ + // bool penetrated = true; + // try + // { + // hitEVA = hit.collider.gameObject.GetComponentUpwards(); + // if (hitEVA != null) + // Debug.Log("[BDArmory]:Hit on kerbal confirmed!"); + // } + // catch (NullReferenceException) + // { + // Debug.Log("[BDArmory]:Whoops ran amok of the exception handler"); + // } + + // if (hitEVA != null) + // { + // float hitAngle = Vector3.Angle(rb.velocity, -hit.normal); + // if (hitEVA.part != null) //see if it will ricochet of the part + // { + // penetrated = !RicochetOnPart(hitEVA.part, hitAngle); + // } + + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////[panzer1b] HEAT BASED DAMAGE CODE START////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // float heatDamage = (rb.mass / hitEVA.part.crashTolerance) * rb.velocity.magnitude * 50 * BDArmorySettings.DMG_MULTIPLIER; //how much heat damage will be applied based on bullet mass, velocity, and part's impact tolerance + + // //how much heat damage will be applied based on bullet mass, velocity, and part's impact tolerance and mass + // if (!penetrated) + // { + // heatDamage = heatDamage / 8; + // } + // if (BDArmorySetup.INSTAKILL) + // //instakill support, will be removed once mod becomes officially MP + // { + // heatDamage = (float)hitEVA.part.maxTemp + 100; + // //make heat damage equal to the part's max temperture, effectively instakilling any part it hits + // } + // if (BDArmorySettings.DRAW_DEBUG_LABELS) + // Debug.Log("[BDArmory]: Hit! damage applied: " + heatDamage); //debugging stuff + + // if (hitEVA.part.vessel != sourceVessel) + // { + // hitEVA.part.AddDamage(heatDamage); + // } + + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////[panzer1b] HEAT BASED DAMAGE CODE END//////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // if (hitEVA.part.vessel != sourceVessel) + // { + // if (!penetrated && !hasBounced) + // { + // //ricochet + // hasBounced = true; + // if BDArmorySettings.BULLET_HITS) + // { + // BulletHitFX.CreateBulletHit(hit.point, hit.normal, true); + // } + + // transform.position = hit.point; + // rb.velocity = Vector3.Reflect(rb.velocity, hit.normal); + // rb.velocity = hitAngle / 150 * rb.velocity * 0.75f; + + // Vector3 randomDirection = UnityEngine.Random.rotation * Vector3.one; + + // rb.velocity = Vector3.RotateTowards(rb.velocity, randomDirection, UnityEngine.Random.Range(0f, 5f) * Mathf.Deg2Rad, 0); + // } + // else + // { + // if BDArmorySettings.BULLET_HITS) + // { + // BulletHitFX.CreateBulletHit(hit.point, hit.normal, false); + // } + + // if (bulletType == BulletTypes.Explosive) + // { + // ExplosionFX.CreateExplosion(hit.point, radius, blastPower, -1, sourceVessel, rb.velocity.normalized, explModelPath, explSoundPath); + // } + + // Destroy(gameObject); //destroy bullet on collision + // } + // } + // } + //} + + if (Physics.Raycast(ray, out hit, dist, 9076737)) { bool penetrated = true; - //hitting a vessel Part - + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////[panzer1b] HEAT BASED DAMAGE CODE START////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Part hitPart = null; //determine when bullet collides with a target try{ - hitPart = Part.FromGO(hit.rigidbody.gameObject); + KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards(); + hitPart = eva ? eva.part : hit.collider.gameObject.GetComponentInParent(); }catch(NullReferenceException){} float hitAngle = Vector3.Angle(rb.velocity, -hit.normal); @@ -184,7 +262,6 @@ void FixedUpdate() } } - if(hitPart!=null && !hitPart.partInfo.name.Contains("Strut")) //when a part is hit, execute damage code (ignores struts to keep those from being abused as armor)(no, because they caused weird bugs :) -BahamutoD) { float heatDamage = (rb.mass/hitPart.crashTolerance) * rb.velocity.magnitude * 50 * BDArmorySettings.DMG_MULTIPLIER; //how much heat damage will be applied based on bullet mass, velocity, and part's impact tolerance @@ -192,27 +269,29 @@ void FixedUpdate() { heatDamage = heatDamage/8; } - if(BDArmorySettings.INSTAKILL) //instakill support, will be removed once mod becomes officially MP + if(BDArmorySetup.INSTAKILL) //instakill support, will be removed once mod becomes officially MP { heatDamage = (float)hitPart.maxTemp + 100; //make heat damage equal to the part's max temperture, effectively instakilling any part it hits } - if (BDArmorySettings.DRAW_DEBUG_LINES) Debug.Log("Hit! damage applied: " + heatDamage); //debugging stuff + if (BDArmorySetup.BDArmorySettings.DRAW_DEBUG_LINES) Debug.Log("[BDArmory]: Hit! damage applied: " + heatDamage); //debugging stuff if (hitPart.mass <= 0.01) //if part mass is below 0.01, instakill it and do minor collateral (anti-exploit and to keep people from abusing near massless or massless crap as armor) { - if (hitPart.vessel != sourceVessel) hitPart.temperature += hitPart.maxTemp + 500; //make heat damage equal to the part's max temperture, and add 500 extra heat damage which should do minor collateral to teh surrounding parts + if (hitPart.vessel != sourceVessel) + { + //make heat damage equal to the part's max temperture, and add 500 extra heat damage which should do minor collateral to teh surrounding parts + hitPart.Destroy(); + } } else //apply damage normally if no special case present { - if (hitPart.vessel != sourceVessel) hitPart.temperature += heatDamage; //apply heat damage to the hit part. + if (hitPart.vessel != sourceVessel) hitPart.AddDamage(heatDamage); //apply heat damage to the hit part. } - } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////[panzer1b] HEAT BASED DAMAGE CODE END//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //hitting a Building DestructibleBuilding hitBuilding = null; @@ -232,85 +311,56 @@ void FixedUpdate() { hitBuilding.Demolish(); } - if(BDArmorySettings.DRAW_DEBUG_LINES) Debug.Log("bullet hit destructible building! Damage: "+(damageToBuilding).ToString("0.00")+ ", total Damage: "+hitBuilding.Damage); + if(BDArmorySetup.BDArmorySettings.DRAW_DEBUG_LINES) Debug.Log("[BDArmory]: bullet hit destructible building! Hitpoints: " + (damageToBuilding).ToString("0.00")+ ", total Hitpoints: "+hitBuilding.Damage); } - + if(hitPart == null || (hitPart!=null && hitPart.vessel!=sourceVessel)) { if(!penetrated && !hasBounced) { //ricochet hasBounced = true; - if(BDArmorySettings.BULLET_HITS) + ifBDArmorySettings.BULLET_HITS) { BulletHitFX.CreateBulletHit(hit.point, hit.normal, true); - } + } transform.position = hit.point; rb.velocity = Vector3.Reflect(rb.velocity, hit.normal); rb.velocity = hitAngle/150 * rb.velocity * 0.75f; - + Vector3 randomDirection = UnityEngine.Random.rotation * Vector3.one; - + rb.velocity = Vector3.RotateTowards(rb.velocity, randomDirection, UnityEngine.Random.Range(0f,5f)*Mathf.Deg2Rad, 0); } else { - if(BDArmorySettings.BULLET_HITS) + ifBDArmorySettings.BULLET_HITS) { BulletHitFX.CreateBulletHit(hit.point, hit.normal, false); } if(bulletType == BulletTypes.Explosive) { - ExplosionFX.CreateExplosion(hit.point, radius, blastPower, sourceVessel, rb.velocity.normalized, explModelPath, explSoundPath); + ExplosionFx.CreateExplosion(hit.point, blastPower, explModelPath, explSoundPath,false); } - GameObject.Destroy(gameObject); //destroy bullet on collision + Destroy(gameObject); //destroy bullet on collision } } } - - /* - if(isUnderwater) - { - if(FlightGlobals.getAltitudeAtPos(transform.position) < 0) - { - isUnderwater = false; - } - else - { - rigidbody.AddForce(-rigidbody.velocity * 0.15f); - } - } - else - { - if(FlightGlobals.getAltitudeAtPos(transform.position) < 0) - { - isUnderwater = true; - //FXMonger.Splash(transform.position, 1); - //make a custom splash here - } - } - */ } if(airDetonation && distanceFromStart > detonationRange) { //detonate - ExplosionFX.CreateExplosion(transform.position, radius, blastPower, sourceVessel, rb.velocity.normalized, explModelPath, explSoundPath); - GameObject.Destroy(gameObject); //destroy bullet on collision + ExplosionFx.CreateExplosion(transform.position, blastPower, explModelPath, explSoundPath,false); + Destroy(gameObject); //destroy bullet on collision } - prevPosition = currPosition; } - - - - - void FadeColor() { Vector4 currentColorV = new Vector4(currentColor.r, currentColor.g, currentColor.b, currentColor.a); @@ -339,3 +389,4 @@ bool RicochetOnPart(Part p, float angleFromNormal) } } +*/ diff --git a/BDArmory/Misc/DecoupledBooster.cs b/BDArmory/Misc/DecoupledBooster.cs new file mode 100644 index 000000000..653b98219 --- /dev/null +++ b/BDArmory/Misc/DecoupledBooster.cs @@ -0,0 +1,37 @@ +using System.Collections; +using System.Collections.Generic; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Misc +{ + public class DecoupledBooster : MonoBehaviour + { + Rigidbody rb; + + IEnumerator SelfDestructRoutine() + { + IEnumerator col = gameObject.GetComponentsInChildren().Cast().GetEnumerator(); + while (col.MoveNext()) + { + if (col.Current == null) continue; + col.Current.enabled = false; + } + col.Dispose(); + yield return new WaitForSeconds(5); + Destroy(gameObject); + } + + public void DecoupleBooster(Vector3 startVelocity, float ejectSpeed) + { + transform.parent = null; + + rb = gameObject.AddComponent(); + gameObject.AddComponent(); + rb.velocity = startVelocity; + rb.velocity += ejectSpeed * transform.forward; + + StartCoroutine(SelfDestructRoutine()); + } + } +} diff --git a/BDArmory/Misc/IBDWeapon.cs b/BDArmory/Misc/IBDWeapon.cs new file mode 100644 index 000000000..44ea295e0 --- /dev/null +++ b/BDArmory/Misc/IBDWeapon.cs @@ -0,0 +1,29 @@ +namespace BDArmory.Misc +{ + public interface IBDWeapon + { + WeaponClasses GetWeaponClass(); + + string GetShortName(); + + string GetSubLabel(); + + string GetMissileType(); + + Part GetPart(); + + // extensions for feature_engagementenvelope + } + + // extensions for feature_engagementenvelope + + public enum WeaponClasses + { + Missile, + Bomb, + Gun, + Rocket, + DefenseLaser, + SLW + } +} diff --git a/BDArmory/Misc/KSPForceApplier.cs b/BDArmory/Misc/KSPForceApplier.cs new file mode 100644 index 000000000..c803985cf --- /dev/null +++ b/BDArmory/Misc/KSPForceApplier.cs @@ -0,0 +1,40 @@ +using UnityEngine; + +namespace BDArmory.Misc +{ + public class KSPForceApplier : MonoBehaviour + { + public float drag = 0.02f; + + Rigidbody rb; + + void Start() + { + rb = GetComponent(); + } + + void FixedUpdate() + { + if (rb != null && !rb.isKinematic) + { + rb.useGravity = false; + + //atmospheric drag (stock) + float simSpeedSquared = rb.velocity.sqrMagnitude; + Vector3 currPos = transform.position; + Vector3 dragForce = (0.008f * rb.mass) * drag * 0.5f * simSpeedSquared * + (float) + FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), + FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody) * + rb.velocity.normalized; + + rb.velocity -= (dragForce / rb.mass) * Time.fixedDeltaTime; + // + + //gravity + if (FlightGlobals.RefFrameIsRotating) + rb.velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; + } + } + } +} diff --git a/BDArmory/Misc/Misc.cs b/BDArmory/Misc/Misc.cs new file mode 100644 index 000000000..6284b710e --- /dev/null +++ b/BDArmory/Misc/Misc.cs @@ -0,0 +1,346 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using BDArmory.Modules; +using BDArmory.UI; +using UniLinq; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace BDArmory.Misc +{ + public static class Misc + { + public static Texture2D resizeTexture = + GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "resizeSquare", false); + + public static Color ParseColor255(string color) + { + Color outputColor = new Color(0, 0, 0, 1); + + string[] strings = color.Split(","[0]); + for (int i = 0; i < 4; i++) + { + outputColor[i] = Single.Parse(strings[i]) / 255; + } + + return outputColor; + } + + public static AnimationState[] SetUpAnimation(string animationName, Part part) //Thanks Majiir! + { + List states = new List(); + IEnumerator animation = part.FindModelAnimators(animationName).AsEnumerable().GetEnumerator(); + while (animation.MoveNext()) + { + if (animation.Current == null) continue; + AnimationState animationState = animation.Current[animationName]; + animationState.speed = 0; + animationState.enabled = true; + animationState.wrapMode = WrapMode.ClampForever; + animation.Current.Blend(animationName); + states.Add(animationState); + } + animation.Dispose(); + return states.ToArray(); + } + + public static AnimationState SetUpSingleAnimation(string animationName, Part part) + { + IEnumerator animation = part.FindModelAnimators(animationName).AsEnumerable().GetEnumerator(); + while (animation.MoveNext()) + { + if (animation.Current == null) continue; + AnimationState animationState = animation.Current[animationName]; + animationState.speed = 0; + animationState.enabled = true; + animationState.wrapMode = WrapMode.ClampForever; + animation.Current.Blend(animationName); + return animationState; + } + animation.Dispose(); + return null; + } + + public static bool CheckMouseIsOnGui() + { + if (!BDArmorySetup.GAME_UI_ENABLED) return false; + + if (!BDInputSettingsFields.WEAP_FIRE_KEY.inputString.Contains("mouse")) return false; + + Vector3 inverseMousePos = new Vector3(Input.mousePosition.x, Screen.height - Input.mousePosition.y, 0); + Rect topGui = new Rect(0, 0, Screen.width, 65); + + if (topGui.Contains(inverseMousePos)) return true; + if (BDArmorySetup.windowBDAToolBarEnabled && BDArmorySetup.WindowRectToolbar.Contains(inverseMousePos)) + return true; + if (ModuleTargetingCamera.windowIsOpen && BDArmorySetup.WindowRectTargetingCam.Contains(inverseMousePos)) + return true; + if (BDArmorySetup.Instance.ActiveWeaponManager) + { + MissileFire wm = BDArmorySetup.Instance.ActiveWeaponManager; + + if (wm.vesselRadarData && wm.vesselRadarData.guiEnabled) + { + if (BDArmorySetup.WindowRectRadar.Contains(inverseMousePos)) return true; + if (wm.vesselRadarData.linkWindowOpen && wm.vesselRadarData.linkWindowRect.Contains(inverseMousePos)) + return true; + } + if (wm.rwr && wm.rwr.rwrEnabled && wm.rwr.displayRWR && BDArmorySetup.WindowRectRwr.Contains(inverseMousePos)) + return true; + if (wm.wingCommander && wm.wingCommander.showGUI) + { + if (BDArmorySetup.WindowRectWingCommander.Contains(inverseMousePos)) return true; + if (wm.wingCommander.showAGWindow && wm.wingCommander.agWindowRect.Contains(inverseMousePos)) + return true; + } + + if (extraGUIRects != null) + { + for (int i = 0; i < extraGUIRects.Count; i++) + { + if (extraGUIRects[i].Contains(inverseMousePos)) return true; + } + } + } + + return false; + } + + public static void ResizeGuiWindow(Rect windowrect, Vector2 mousePos) + { + } + + public static List extraGUIRects; + + public static int RegisterGUIRect(Rect rect) + { + if (extraGUIRects == null) + { + extraGUIRects = new List(); + } + + int index = extraGUIRects.Count; + extraGUIRects.Add(rect); + return index; + } + + public static void UpdateGUIRect(Rect rect, int index) + { + if (extraGUIRects == null) + { + Debug.LogWarning("Trying to update a GUI rect for mouse position check, but Rect list is null."); + } + + extraGUIRects[index] = rect; + } + + public static bool MouseIsInRect(Rect rect) + { + Vector3 inverseMousePos = new Vector3(Input.mousePosition.x, Screen.height - Input.mousePosition.y, 0); + return rect.Contains(inverseMousePos); + } + + //Thanks FlowerChild + //refreshes part action window + public static void RefreshAssociatedWindows(Part part) + { + IEnumerator window = Object.FindObjectsOfType(typeof(UIPartActionWindow)).Cast().GetEnumerator(); + while (window.MoveNext()) + { + if (window.Current == null) continue; + if (window.Current.part == part) + { + window.Current.displayDirty = true; + } + } + window.Dispose(); + } + + public static Vector3 ProjectOnPlane(Vector3 point, Vector3 planePoint, Vector3 planeNormal) + { + planeNormal = planeNormal.normalized; + + Plane plane = new Plane(planeNormal, planePoint); + float distance = plane.GetDistanceToPoint(point); + + return point - (distance * planeNormal); + } + + public static float SignedAngle(Vector3 fromDirection, Vector3 toDirection, Vector3 referenceRight) + { + float angle = Vector3.Angle(fromDirection, toDirection); + float sign = Mathf.Sign(Vector3.Dot(toDirection, referenceRight)); + float finalAngle = sign * angle; + return finalAngle; + } + + /// + /// Parses the string to a curve. + /// Format: "key:pair,key:pair" + /// + /// The curve. + /// Curve string. + public static FloatCurve ParseCurve(string curveString) + { + string[] pairs = curveString.Split(new char[] { ',' }); + Keyframe[] keys = new Keyframe[pairs.Length]; + for (int p = 0; p < pairs.Length; p++) + { + string[] pair = pairs[p].Split(new char[] { ':' }); + keys[p] = new Keyframe(float.Parse(pair[0]), float.Parse(pair[1])); + } + + FloatCurve curve = new FloatCurve(keys); + + return curve; + } + + public static bool CheckSightLine(Vector3 origin, Vector3 target, float maxDistance, float threshold, + float startDistance) + { + float dist = maxDistance; + Ray ray = new Ray(origin, target - origin); + ray.origin += ray.direction * startDistance; + RaycastHit rayHit; + if (Physics.Raycast(ray, out rayHit, dist, 9076737)) + { + if ((target - rayHit.point).sqrMagnitude < threshold * threshold) + { + return true; + } + else + { + return false; + } + } + + return false; + } + + public static bool CheckSightLineExactDistance(Vector3 origin, Vector3 target, float maxDistance, + float threshold, float startDistance) + { + float dist = maxDistance; + Ray ray = new Ray(origin, target - origin); + ray.origin += ray.direction * startDistance; + RaycastHit rayHit; + + if (Physics.Raycast(ray, out rayHit, dist, 9076737)) + { + if ((target - rayHit.point).sqrMagnitude < threshold * threshold) + { + return true; + } + else + { + return false; + } + } + + return true; + } + + public static float[] ParseToFloatArray(string floatString) + { + string[] floatStrings = floatString.Split(new char[] { ',' }); + float[] floatArray = new float[floatStrings.Length]; + for (int i = 0; i < floatStrings.Length; i++) + { + floatArray[i] = float.Parse(floatStrings[i]); + } + + return floatArray; + } + + public static string FormattedGeoPos(Vector3d geoPos, bool altitude) + { + string finalString = string.Empty; + //lat + double lat = geoPos.x; + double latSign = Math.Sign(lat); + double latMajor = latSign * Math.Floor(Math.Abs(lat)); + double latMinor = 100 * (Math.Abs(lat) - Math.Abs(latMajor)); + string latString = latMajor.ToString("0") + " " + latMinor.ToString("0.000"); + finalString += "N:" + latString; + + //longi + double longi = geoPos.y; + double longiSign = Math.Sign(longi); + double longiMajor = longiSign * Math.Floor(Math.Abs(longi)); + double longiMinor = 100 * (Math.Abs(longi) - Math.Abs(longiMajor)); + string longiString = longiMajor.ToString("0") + " " + longiMinor.ToString("0.000"); + finalString += " E:" + longiString; + + if (altitude) + { + finalString += " ASL:" + geoPos.z.ToString("0.000"); + } + + return finalString; + } + + public static string FormattedGeoPosShort(Vector3d geoPos, bool altitude) + { + string finalString = string.Empty; + //lat + double lat = geoPos.x; + double latSign = Math.Sign(lat); + double latMajor = latSign * Math.Floor(Math.Abs(lat)); + double latMinor = 100 * (Math.Abs(lat) - Math.Abs(latMajor)); + string latString = latMajor.ToString("0") + " " + latMinor.ToString("0"); + finalString += "N:" + latString; + + //longi + double longi = geoPos.y; + double longiSign = Math.Sign(longi); + double longiMajor = longiSign * Math.Floor(Math.Abs(longi)); + double longiMinor = 100 * (Math.Abs(longi) - Math.Abs(longiMajor)); + string longiString = longiMajor.ToString("0") + " " + longiMinor.ToString("0"); + finalString += " E:" + longiString; + + if (altitude) + { + finalString += " ASL:" + geoPos.z.ToString("0"); + } + + return finalString; + } + + public static KeyBinding AGEnumToKeybinding(KSPActionGroup group) + { + string groupName = group.ToString(); + if (groupName.Contains("Custom")) + { + groupName = groupName.Substring(6); + int customNumber = int.Parse(groupName); + groupName = "CustomActionGroup" + customNumber; + } + else + { + return null; + } + + FieldInfo field = typeof(GameSettings).GetField(groupName); + return (KeyBinding)field.GetValue(null); + } + + public static float GetRadarAltitudeAtPos(Vector3 position) + { + double latitudeAtPos = FlightGlobals.currentMainBody.GetLatitude(position); + double longitudeAtPos = FlightGlobals.currentMainBody.GetLongitude(position); + float altitude = (float)(FlightGlobals.currentMainBody.GetAltitude(position)); + return Mathf.Clamp(altitude - (float)FlightGlobals.currentMainBody.TerrainAltitude(latitudeAtPos, longitudeAtPos), 0, altitude); + } + + public static string JsonCompat(string json) + { + return json.Replace('{', '<').Replace('}', '>'); + } + + public static string JsonDecompat(string json) + { + return json.Replace('<', '{').Replace('>', '}'); + } + } +} diff --git a/BDArmory/Misc/MissileLaunchParams.cs b/BDArmory/Misc/MissileLaunchParams.cs new file mode 100644 index 000000000..9bd295da9 --- /dev/null +++ b/BDArmory/Misc/MissileLaunchParams.cs @@ -0,0 +1,71 @@ +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Misc +{ + public struct MissileLaunchParams + { + public float minLaunchRange; + public float maxLaunchRange; + + private float rtr; + + /// + /// Gets the maximum no-escape range. + /// + /// The max no-escape range. + public float rangeTr + { + get + { + return rtr; + } + } + + public MissileLaunchParams(float min, float max) + { + minLaunchRange = min; + maxLaunchRange = max; + rtr = (max + min) / 2; + } + + /// + /// Gets the dynamic launch parameters. + /// + /// The dynamic launch parameters. + /// Launcher velocity. + /// Target velocity. + public static MissileLaunchParams GetDynamicLaunchParams(MissileBase missile, Vector3 targetVelocity, Vector3 targetPosition) + { + Vector3 launcherVelocity = missile.vessel.Velocity(); + float launcherSpeed = (float)missile.vessel.srfSpeed; + float minLaunchRange = missile.minStaticLaunchRange; + float maxLaunchRange = missile.maxStaticLaunchRange; + + float rangeAddMin = 0; + float rangeAddMax = 0; + float relSpeed; + + Vector3 relV = targetVelocity - launcherVelocity; + Vector3 vectorToTarget = targetPosition - missile.part.transform.position; + Vector3 relVProjected = Vector3.Project(relV, vectorToTarget); + relSpeed = -Mathf.Sign(Vector3.Dot(relVProjected, vectorToTarget)) * relVProjected.magnitude; + + rangeAddMin += relSpeed * 2; + rangeAddMax += relSpeed * 8; + rangeAddMin += launcherSpeed * 2; + rangeAddMax += launcherSpeed * 2; + + double diffAlt = missile.vessel.altitude - FlightGlobals.getAltitudeAtPos(targetPosition); + + rangeAddMax += (float)diffAlt; + + float min = Mathf.Clamp(minLaunchRange + rangeAddMin, 0, BDArmorySettings.MAX_ENGAGEMENT_RANGE); + float max = Mathf.Clamp(maxLaunchRange + rangeAddMax, min + 100, BDArmorySettings.MAX_ENGAGEMENT_RANGE); + + return new MissileLaunchParams(min, max); + } + } +} diff --git a/BDArmory/Misc/ObjectPool.cs b/BDArmory/Misc/ObjectPool.cs new file mode 100644 index 000000000..780d98ceb --- /dev/null +++ b/BDArmory/Misc/ObjectPool.cs @@ -0,0 +1,96 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace BDArmory.Misc +{ + public class ObjectPool : MonoBehaviour + { + public GameObject poolObject; + public int size; + public bool canGrow; + + List pool; + + public string poolObjectName; + + void Awake() + { + pool = new List(); + } + + void Start() + { + for (int i = 0; i < size; i++) + { + GameObject obj = Instantiate(poolObject); + obj.transform.SetParent(transform); + obj.SetActive(false); + pool.Add(obj); + } + } + + public GameObject GetPooledObject(int index) + { + return pool[index]; + } + + public GameObject GetPooledObject() + { + if (canGrow) + { + if (!poolObject) + { + Debug.LogWarning("Tried to instantiate a pool object but prefab is missing! (" + poolObjectName + ")"); + } + + GameObject obj = Instantiate(poolObject); + obj.SetActive(false); + pool.Add(obj); + size++; + + return obj; + } + + for (int i = 0; i < pool.Count; i++) + { + if (!pool[i].activeInHierarchy) + { + return pool[i]; + } + } + + return null; + } + + public void DisableAfterDelay(GameObject obj, float t) + { + StartCoroutine(DisableObject(obj, t)); + } + + IEnumerator DisableObject(GameObject obj, float t) + { + yield return new WaitForSeconds(t); + if (obj) + { + obj.SetActive(false); + obj.transform.parent = transform; + } + } + + public static ObjectPool CreateObjectPool(GameObject obj, int size, bool canGrow, bool destroyOnLoad, bool disableAfterDelay = false) + { + GameObject poolObject = new GameObject(obj.name + "Pool"); + ObjectPool op = poolObject.AddComponent(); + op.poolObject = obj; + op.size = size; + op.canGrow = canGrow; + op.poolObjectName = obj.name; + if (!destroyOnLoad) + { + DontDestroyOnLoad(poolObject); + } + return op; + } + } +} diff --git a/BDArmory/Misc/RippleOption.cs b/BDArmory/Misc/RippleOption.cs new file mode 100644 index 000000000..a33a3466c --- /dev/null +++ b/BDArmory/Misc/RippleOption.cs @@ -0,0 +1,14 @@ +namespace BDArmory.Misc +{ + public class RippleOption + { + public bool rippleFire; + public float rpm; + + public RippleOption(bool rippleFire, float rpm) + { + this.rippleFire = rippleFire; + this.rpm = rpm; + } + } +} diff --git a/BDArmory/Misc/VectorUtils.cs b/BDArmory/Misc/VectorUtils.cs new file mode 100644 index 000000000..ef25f66e0 --- /dev/null +++ b/BDArmory/Misc/VectorUtils.cs @@ -0,0 +1,278 @@ +using System; +using UnityEngine; + +namespace BDArmory.Misc +{ + public static class VectorUtils + { + private static System.Random RandomGen = new System.Random(); + + /// Right compared to fromDirection, make sure it's not orthogonal to toDirection, or you'll get unstable signs + public static float SignedAngle(Vector3 fromDirection, Vector3 toDirection, Vector3 referenceRight) + { + float angle = Vector3.Angle(fromDirection, toDirection); + float sign = Mathf.Sign(Vector3.Dot(toDirection, referenceRight)); + float finalAngle = sign * angle; + return finalAngle; + } + + /// + /// Same as SignedAngle, just using double precision for the cosine calculation. + /// For very small angles the floating point precision starts to matter, as the cosine is close to 1, not to 0. + /// + public static float SignedAngleDP(Vector3 fromDirection, Vector3 toDirection, Vector3 referenceRight) + { + float angle = (float)Vector3d.Angle(fromDirection, toDirection); + float sign = Mathf.Sign(Vector3.Dot(toDirection, referenceRight)); + float finalAngle = sign * angle; + return finalAngle; + } + + /// + /// Convert an angle to be between -180 and 180. + /// + public static float ToAngle(this float angle) + { + angle = (angle + 180) % 360; + return angle > 0 ? angle - 180 : angle + 180; + } + + //from howlingmoonsoftware.com + //calculates how long it will take for a target to be where it will be when a bullet fired now can reach it. + //delta = initial relative position, vr = relative velocity, muzzleV = bullet velocity. + public static float CalculateLeadTime(Vector3 delta, Vector3 vr, float muzzleV) + { + // Quadratic equation coefficients a*t^2 + b*t + c = 0 + float a = Vector3.Dot(vr, vr) - muzzleV * muzzleV; + float b = 2f * Vector3.Dot(vr, delta); + float c = Vector3.Dot(delta, delta); + + float det = b * b - 4f * a * c; + + // If the determinant is negative, then there is no solution + if (det > 0f) + { + return 2f * c / (Mathf.Sqrt(det) - b); + } + else + { + return -1f; + } + } + + /// + /// Returns a value between -1 and 1 via Perlin noise. + /// + /// Returns a value between -1 and 1 via Perlin noise. + /// The x coordinate. + /// The y coordinate. + public static float FullRangePerlinNoise(float x, float y) + { + float perlin = Mathf.PerlinNoise(x, y); + + perlin -= 0.5f; + perlin *= 2; + + return perlin; + } + + public static Vector3 RandomDirectionDeviation(Vector3 direction, float maxAngle) + { + return Vector3.RotateTowards(direction, UnityEngine.Random.rotation * direction, UnityEngine.Random.Range(0, maxAngle * Mathf.Deg2Rad), 0).normalized; + } + + public static Vector3 WeightedDirectionDeviation(Vector3 direction, float maxAngle) + { + float random = UnityEngine.Random.Range(0f, 1f); + float maxRotate = maxAngle * (random * random); + maxRotate = Mathf.Clamp(maxRotate, 0, maxAngle) * Mathf.Deg2Rad; + return Vector3.RotateTowards(direction, Vector3.ProjectOnPlane(UnityEngine.Random.onUnitSphere, direction), maxRotate, 0).normalized; + } + + /// + /// Returns the original vector rotated in a random direction using the give standard deviation. + /// + /// mean direction + /// standard deviation in degrees + /// Randomly adjusted Vector3 + /// + /// Technically, this is calculated using the chi-squared distribution in polar coordinates, + /// which, incidentally, makes the math easier too. + /// However a chi-squared (k=2) distance from center distribution produces a vector distributed normally + /// on any chosen axis orthogonal to the original vector, which is exactly what we want. + /// + public static Vector3 GaussianDirectionDeviation(Vector3 direction, float standardDeviation) + { + return Quaternion.AngleAxis(UnityEngine.Random.Range(-180f, 180f), direction) + * Quaternion.AngleAxis(Rayleigh() * standardDeviation, + new Vector3(-1 / direction.x, -1 / direction.y, 2 / direction.z)) // orthogonal vector + * direction; + } + + /// Random float distributed with an approximated standard normal distribution + /// https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + /// Note a standard normal variable is technically unbounded + public static float Gaussian() + { + // Technically this will raise an exception if the first random produces a zero + try + { + return Mathf.Sqrt(-2 * Mathf.Log(UnityEngine.Random.value)) * Mathf.Cos(Mathf.PI * UnityEngine.Random.value); + } + catch (Exception) + { // I have no idea what exception Mathf.Log raises when it gets a zero + return 0; + } + } + + /// + /// Random float distributed with the chi-squared distribution with two degrees of freedom + /// aka the Rayleigh distribution. + /// Multiply by deviation for best results. + /// + /// https://en.wikipedia.org/wiki/Rayleigh_distribution + /// Note a chi-square distributed variable is technically unbounded + public static float Rayleigh() + { + // Technically this will raise an exception if the random produces a zero, which should almost never happen + try + { + return Mathf.Sqrt(-2 * Mathf.Log(UnityEngine.Random.value)); + } + catch (Exception) + { // I have no idea what exception Mathf.Log raises when it gets a zero + return 0; + } + } + + /// + /// Converts world position to Lat,Long,Alt form. + /// + /// The position in geo coords. + /// World position. + /// Body. + public static Vector3d WorldPositionToGeoCoords(Vector3d worldPosition, CelestialBody body) + { + if (!body) + { + //Debug.Log ("BahaTurret.VectorUtils.WorldPositionToGeoCoords body is null"); + return Vector3d.zero; + } + + double lat = body.GetLatitude(worldPosition); + double longi = body.GetLongitude(worldPosition); + double alt = body.GetAltitude(worldPosition); + return new Vector3d(lat, longi, alt); + } + + /// + /// Calculates the coordinates of a point a certain distance away in a specified direction. + /// + /// Starting point coordinates, in Lat,Long,Alt form + /// The body on which the movement is happening + /// Bearing to move in, in degrees, where 0 is north and 90 is east + /// Distance to move, in meters + /// Ending point coordinates, in Lat,Long,Alt form + public static Vector3 GeoCoordinateOffset(Vector3 start, CelestialBody body, float bearing, float distance) + { + //https://stackoverflow.com/questions/2637023/how-to-calculate-the-latlng-of-a-point-a-certain-distance-away-from-another + float lat1 = start.x * Mathf.Deg2Rad; + float lon1 = start.y * Mathf.Deg2Rad; + bearing *= Mathf.Deg2Rad; + distance /= ((float)body.Radius + start.z); + + float lat2 = Mathf.Asin(Mathf.Sin(lat1) * Mathf.Cos(distance) + Mathf.Cos(lat1) * Mathf.Sin(distance) * Mathf.Cos(bearing)); + float lon2 = lon1 + Mathf.Atan2(Mathf.Sin(bearing) * Mathf.Sin(distance) * Mathf.Cos(lat1), Mathf.Cos(distance) - Mathf.Sin(lat1) * Mathf.Sin(lat2)); + + return new Vector3(lat2 * Mathf.Rad2Deg, lon2 * Mathf.Rad2Deg, start.z); + } + + /// + /// Calculate the bearing going from one point to another + /// + /// Starting point coordinates, in Lat,Long,Alt form + /// Destination point coordinates, in Lat,Long,Alt form + /// Bearing when looking at destination from start, in degrees, where 0 is north and 90 is east + public static float GeoForwardAzimuth(Vector3 start, Vector3 destination) + { + //http://www.movable-type.co.uk/scripts/latlong.html + float lat1 = start.x * Mathf.Deg2Rad; + float lon1 = start.y * Mathf.Deg2Rad; + float lat2 = destination.x * Mathf.Deg2Rad; + float lon2 = destination.y * Mathf.Deg2Rad; + return Mathf.Atan2(Mathf.Sin(lon2 - lon1) * Mathf.Cos(lat2), Mathf.Cos(lat1) * Mathf.Sin(lat2) - Mathf.Sin(lat1) * Mathf.Cos(lat2) * Mathf.Cos(lon2 - lon1)) * Mathf.Rad2Deg; + } + + /// + /// Calculate the distance from one point to another on a globe + /// + /// Starting point coordinates, in Lat,Long,Alt form + /// Destination point coordinates, in Lat,Long,Alt form + /// The body on which the distance is calculated + /// distance between the two points + public static float GeoDistance(Vector3 start, Vector3 destination, CelestialBody body) + { + //http://www.movable-type.co.uk/scripts/latlong.html + float lat1 = start.x * Mathf.Deg2Rad; + float lat2 = destination.x * Mathf.Deg2Rad; + float dlat = lat2 - lat1; + float dlon = (destination.y - start.y) * Mathf.Deg2Rad; + float a = Mathf.Sin(dlat / 2) * Mathf.Sin(dlat / 2) + Mathf.Cos(lat1) * Mathf.Cos(lat2) * Mathf.Sin(dlon / 2) * Mathf.Sin(dlon / 2); + float distance = 2 * Mathf.Atan2(Mathf.Sqrt(a), Mathf.Sqrt(1 - a)) * (float)body.Radius; + return Mathf.Sqrt(distance * distance + (destination.z - start.z) * (destination.z - start.z)); + } + + public static Vector3 RotatePointAround(Vector3 pointToRotate, Vector3 pivotPoint, Vector3 axis, float angle) + { + Vector3 line = pointToRotate - pivotPoint; + line = Quaternion.AngleAxis(angle, axis) * line; + return pivotPoint + line; + } + + public static Vector3 GetNorthVector(Vector3 position, CelestialBody body) + { + Vector3 geoPosA = WorldPositionToGeoCoords(position, body); + Vector3 geoPosB = new Vector3(geoPosA.x + 1, geoPosA.y, geoPosA.z); + Vector3 north = GetWorldSurfacePostion(geoPosB, body) - GetWorldSurfacePostion(geoPosA, body); + return Vector3.ProjectOnPlane(north, body.GetSurfaceNVector(geoPosA.x, geoPosA.y)).normalized; + } + + public static Vector3 GetWorldSurfacePostion(Vector3d geoPosition, CelestialBody body) + { + if (!body) + { + return Vector3.zero; + } + return body.GetWorldSurfacePosition(geoPosition.x, geoPosition.y, geoPosition.z); + } + + public static Vector3 GetUpDirection(Vector3 position) + { + if (FlightGlobals.currentMainBody == null) return Vector3.up; + return (position - FlightGlobals.currentMainBody.transform.position).normalized; + } + + public static bool SphereRayIntersect(Ray ray, Vector3 sphereCenter, double sphereRadius, out double distance) + { + Vector3 o = ray.origin; + Vector3 l = ray.direction; + Vector3d c = sphereCenter; + double r = sphereRadius; + + double d; + + d = -(Vector3.Dot(l, o - c) + Math.Sqrt(Mathf.Pow(Vector3.Dot(l, o - c), 2) - (o - c).sqrMagnitude + (r * r))); + + if (double.IsNaN(d)) + { + distance = 0; + return false; + } + else + { + distance = d; + return true; + } + } + } +} diff --git a/BDArmory/Misc/ViewScanResults.cs b/BDArmory/Misc/ViewScanResults.cs new file mode 100644 index 000000000..580a56f13 --- /dev/null +++ b/BDArmory/Misc/ViewScanResults.cs @@ -0,0 +1,18 @@ +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Misc +{ + public struct ViewScanResults + { + public bool foundMissile; + public bool foundHeatMissile; + public bool foundRadarMissile; + public bool foundAGM; + public bool firingAtMe; + public float missileThreatDistance; + public Vector3 threatPosition; + public Vessel threatVessel; + public MissileFire threatWeaponManager; + } +} diff --git a/BDArmory/Misc/WMTurretGroup.cs b/BDArmory/Misc/WMTurretGroup.cs new file mode 100644 index 000000000..27201d7c7 --- /dev/null +++ b/BDArmory/Misc/WMTurretGroup.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Misc +{ + public class WMTurretGroup : MonoBehaviour + { + public enum TargetTypes + { + Air, + Ground, + Missiles, + All + } + + public List weapons; + + public bool guardMode = false; + public TargetTypes targetType = TargetTypes.All; + + public void StartFiringOnTarget(Vessel targetVessel, float burstLength) + { + List.Enumerator weapon = weapons.GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + weapon.Current.visualTargetVessel = targetVessel; + weapon.Current.autoFireTimer = Time.time; + weapon.Current.autoFireLength = burstLength; + } + weapon.Dispose(); + } + + public void ForceStopFiring() + { + List.Enumerator weapon = weapons.GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + weapon.Current.autoFire = false; + weapon.Current.visualTargetVessel = null; + } + weapon.Dispose(); + } + } +} diff --git a/BDArmory/Modules/Animation/BDALookConstraintUp.cs b/BDArmory/Modules/Animation/BDALookConstraintUp.cs new file mode 100644 index 000000000..a19b1490e --- /dev/null +++ b/BDArmory/Modules/Animation/BDALookConstraintUp.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace BDArmory.Modules.Animation +{ + public class BDALookConstraintUp : PartModule + { + [KSPField(isPersistant = false)] public string targetName; + + [KSPField(isPersistant = false)] public string rotatorsName; + + Transform target; + Transform rotator; + + public void Start() + { + target = part.FindModelTransform(targetName); + rotator = part.FindModelTransform(rotatorsName); + } + + public void FixedUpdate() + { + Vector3 upAxisV = rotator.up; + + rotator.LookAt(target, upAxisV); + } + } +} diff --git a/BDArmory/Modules/Animation/BDAScaleByDistance.cs b/BDArmory/Modules/Animation/BDAScaleByDistance.cs new file mode 100644 index 000000000..47f396bfb --- /dev/null +++ b/BDArmory/Modules/Animation/BDAScaleByDistance.cs @@ -0,0 +1,48 @@ +using UnityEngine; + +namespace BDArmory.Modules.Animation +{ + public class BDAScaleByDistance : PartModule + { + [KSPField(isPersistant = false)] public string transformToScaleName; + + public Transform transformToScale; + + [KSPField(isPersistant = false)] public string scaleFactor = "0,0,1"; + Vector3 scaleFactorV; + + [KSPField(isPersistant = false)] public string distanceTransformName; + + public Transform distanceTransform; + + public override void OnStart(StartState state) + { + ParseScale(); + transformToScale = part.FindModelTransform(transformToScaleName); + distanceTransform = part.FindModelTransform(distanceTransformName); + } + + public void FixedUpdate() + { + Vector3 finalScaleFactor; + float distance = Vector3.Distance(transformToScale.position, distanceTransform.position); + float sfX = (scaleFactorV.x != 0) ? scaleFactorV.x * distance : 1; + float sfY = (scaleFactorV.y != 0) ? scaleFactorV.y * distance : 1; + float sfZ = (scaleFactorV.z != 0) ? scaleFactorV.z * distance : 1; + finalScaleFactor = new Vector3(sfX, sfY, sfZ); + + transformToScale.localScale = finalScaleFactor; + } + + void ParseScale() + { + string[] split = scaleFactor.Split(','); + float[] splitF = new float[split.Length]; + for (int i = 0; i < split.Length; i++) + { + splitF[i] = float.Parse(split[i]); + } + scaleFactorV = new Vector3(splitF[0], splitF[1], splitF[2]); + } + } +} diff --git a/BDArmory/Modules/BDACategoryModule.cs b/BDArmory/Modules/BDACategoryModule.cs new file mode 100644 index 000000000..c9fbd3765 --- /dev/null +++ b/BDArmory/Modules/BDACategoryModule.cs @@ -0,0 +1,7 @@ +namespace BDArmory.Modules +{ + public class BDACategoryModule : PartModule + { + //dummy + } +} \ No newline at end of file diff --git a/BDArmory/Modules/BDAdjustableRail.cs b/BDArmory/Modules/BDAdjustableRail.cs new file mode 100644 index 000000000..2539c539c --- /dev/null +++ b/BDArmory/Modules/BDAdjustableRail.cs @@ -0,0 +1,156 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class BDAdjustableRail : PartModule + { + [KSPField(isPersistant = true)] public float railHeight; + + [KSPField(isPersistant = true)] public float railLength = 1; + + Transform railLengthTransform; + Transform railHeightTransform; + + [KSPField] public string stackNodePosition; + + Dictionary originalStackNodePosition; + + public override void OnStart(StartState state) + { + railLengthTransform = part.FindModelTransform("Rail"); + railHeightTransform = part.FindModelTransform("RailSleeve"); + + railLengthTransform.localScale = new Vector3(1, railLength, 1); + railHeightTransform.localPosition = new Vector3(0, railHeight, 0); + + if (HighLogic.LoadedSceneIsEditor) + { + ParseStackNodePosition(); + StartCoroutine(DelayedUpdateStackNode()); + } + } + + void ParseStackNodePosition() + { + originalStackNodePosition = new Dictionary(); + string[] nodes = stackNodePosition.Split(new char[] { ';' }); + for (int i = 0; i < nodes.Length; i++) + { + string[] split = nodes[i].Split(new char[] { ',' }); + string id = split[0]; + Vector3 position = new Vector3(float.Parse(split[1]), float.Parse(split[2]), float.Parse(split[3])); + originalStackNodePosition.Add(id, position); + } + } + + IEnumerator DelayedUpdateStackNode() + { + yield return null; + UpdateStackNode(false); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_IncreaseHeight", active = true)]//Height ++ + public void IncreaseHeight() + { + railHeight = Mathf.Clamp(railHeight - 0.02f, -.16f, 0); + railHeightTransform.localPosition = new Vector3(0, railHeight, 0); + + UpdateStackNode(true); + + List.Enumerator sym = part.symmetryCounterparts.GetEnumerator(); + while (sym.MoveNext()) + { + if (sym.Current == null) continue; + sym.Current.FindModuleImplementing().UpdateHeight(railHeight); + } + sym.Dispose(); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DecreaseHeight", active = true)]//Height -- + public void DecreaseHeight() + { + railHeight = Mathf.Clamp(railHeight + 0.02f, -.16f, 0); + railHeightTransform.localPosition = new Vector3(0, railHeight, 0); + + UpdateStackNode(true); + + List.Enumerator sym = part.symmetryCounterparts.GetEnumerator(); + while (sym.MoveNext()) + { + if (sym.Current == null) continue; + sym.Current.FindModuleImplementing().UpdateHeight(railHeight); + } + sym.Dispose(); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_IncreaseLength", active = true)]//Length ++ + public void IncreaseLength() + { + railLength = Mathf.Clamp(railLength + 0.2f, 0.4f, 2f); + railLengthTransform.localScale = new Vector3(1, railLength, 1); + List.Enumerator sym = part.symmetryCounterparts.GetEnumerator(); + while (sym.MoveNext()) + { + if (sym.Current == null) continue; + sym.Current.FindModuleImplementing().UpdateLength(railLength); + } + sym.Dispose(); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DecreaseLength", active = true)]//Length -- + public void DecreaseLength() + { + railLength = Mathf.Clamp(railLength - 0.2f, 0.4f, 2f); + railLengthTransform.localScale = new Vector3(1, railLength, 1); + List.Enumerator sym = part.symmetryCounterparts.GetEnumerator(); + while (sym.MoveNext()) + { + if (sym.Current == null) continue; + sym.Current.FindModuleImplementing().UpdateLength(railLength); + } + sym.Dispose(); + } + + public void UpdateHeight(float height) + { + railHeight = height; + railHeightTransform.localPosition = new Vector3(0, railHeight, 0); + + UpdateStackNode(true); + } + + public void UpdateLength(float length) + { + railLength = length; + railLengthTransform.localScale = new Vector3(1, railLength, 1); + } + + public void UpdateStackNode(bool updateChild) + { + Vector3 delta = Vector3.zero; + List.Enumerator stackNode = part.attachNodes.GetEnumerator(); + while (stackNode.MoveNext()) + { + if (stackNode.Current?.nodeType != AttachNode.NodeType.Stack || + !originalStackNodePosition.ContainsKey(stackNode.Current.id)) continue; + Vector3 prevPos = stackNode.Current.position; + + stackNode.Current.position.y = originalStackNodePosition[stackNode.Current.id].y + railHeight; + delta = stackNode.Current.position - prevPos; + } + stackNode.Dispose(); + + if (!updateChild) return; + Vector3 worldDelta = part.transform.TransformVector(delta); + List.Enumerator p = part.children.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + p.Current.transform.position += worldDelta; + } + p.Dispose(); + } + } +} diff --git a/BDArmory/Modules/BDExplosivePart.cs b/BDArmory/Modules/BDExplosivePart.cs new file mode 100644 index 000000000..f66a8bdb5 --- /dev/null +++ b/BDArmory/Modules/BDExplosivePart.cs @@ -0,0 +1,135 @@ +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Core.Utils; +using BDArmory.FX; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class BDExplosivePart : PartModule + { + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_TNTMass"),//TNT mass equivalent + UI_Label(affectSymCounterparts = UI_Scene.All, controlEnabled = true, scene = UI_Scene.All)] + public float tntMass = 1; + + [KSPField(isPersistant = false, guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_BlastRadius"),//Blast Radius + UI_Label(affectSymCounterparts = UI_Scene.All, controlEnabled = true, scene = UI_Scene.All)] + public float blastRadius = 10; + + [KSPField] + public string explModelPath = "BDArmory/Models/explosion/explosion"; + + [KSPField] + public string explSoundPath = "BDArmory/Sounds/explode1"; + + [KSPAction("Arm")] + public void ArmAG(KSPActionParam param) + { + Armed = true; + } + + [KSPAction("Detonate")] + public void DetonateAG(KSPActionParam param) + { + Detonate(); + } + + [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_Detonate", active = true)]//Detonate + public void DetonateEvent() + { + Detonate(); + } + + public bool Armed { get; set; } = true; + public bool Shaped { get; set; } = false; + + private double previousMass = -1; + + bool hasDetonated; + + public override void OnStart(StartState state) + { + if (HighLogic.LoadedSceneIsFlight) + { + part.explosionPotential = 1.0f; + part.OnJustAboutToBeDestroyed += DetonateIfPossible; + part.force_activate(); + } + + if (BDArmorySettings.ADVANCED_EDIT) + { + //Fields["tntMass"].guiActiveEditor = true; + + //((UI_FloatRange)Fields["tntMass"].uiControlEditor).minValue = 0f; + //((UI_FloatRange)Fields["tntMass"].uiControlEditor).maxValue = 3000f; + //((UI_FloatRange)Fields["tntMass"].uiControlEditor).stepIncrement = 5f; + } + + CalculateBlast(); + } + + public void Update() + { + if (HighLogic.LoadedSceneIsEditor) + { + OnUpdateEditor(); + } + + if (hasDetonated) + { + this.part.explode(); + } + } + + private void OnUpdateEditor() + { + CalculateBlast(); + } + + private void CalculateBlast() + { + if (part.Resources.Contains("HighExplosive")) + { + if (part.Resources["HighExplosive"].amount == previousMass) return; + + tntMass = (float)(part.Resources["HighExplosive"].amount * part.Resources["HighExplosive"].info.density * 1000) * 1.5f; + part.explosionPotential = tntMass / 10f; + previousMass = part.Resources["HighExplosive"].amount; + } + + blastRadius = BlastPhysicsUtils.CalculateBlastRange(tntMass); + } + + public void DetonateIfPossible() + { + if (!hasDetonated && Armed) + { + Vector3 direction = default(Vector3); + + if (Shaped) + { + direction = (part.transform.position + part.rb.velocity * Time.deltaTime).normalized; + } + ExplosionFx.CreateExplosion(part.transform.position, tntMass, + explModelPath, explSoundPath, true, 0, part, direction); + hasDetonated = true; + } + } + + private void Detonate() + { + if (!hasDetonated && Armed) + { + part.Destroy(); + ExplosionFx.CreateExplosion(part.transform.position, tntMass, + explModelPath, explSoundPath, true, 0, part); + } + } + + public float GetBlastRadius() + { + CalculateBlast(); + return blastRadius; + } + } +} diff --git a/BDArmory/Modules/BDGenericAIBase.cs b/BDArmory/Modules/BDGenericAIBase.cs new file mode 100644 index 000000000..b70fdc63c --- /dev/null +++ b/BDArmory/Modules/BDGenericAIBase.cs @@ -0,0 +1,382 @@ +using System; +using System.Text; +using BDArmory.Control; +using BDArmory.Core; +using BDArmory.Misc; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; +using KSP.Localization; + +namespace BDArmory.Modules +{ + /// + /// A base class for implementing AI. + /// Note: You do not have to use it, it is just for convenience, all the game cares about is that you implement the IBDAIControl interface. + /// + public abstract class BDGenericAIBase : PartModule, IBDAIControl, IBDWMModule + { + #region declarations + + public bool pilotEnabled => pilotOn; + + // separate private field for pilot On, because properties cannot be KSPFields + [KSPField(isPersistant = true)] + public bool pilotOn; + protected Vessel activeVessel; + + public MissileFire weaponManager { get; protected set; } + + /// + /// The default is BDAirspeedControl. If you want to use something else, just override ActivatePilot (and, potentially, DeactivatePilot), and make it use something else. + /// + protected BDAirspeedControl speedController; + + protected Transform vesselTransform => vessel.ReferenceTransform; + + protected StringBuilder debugString = new StringBuilder(); + + protected Vessel targetVessel; + + protected virtual Vector3d assignedPositionGeo { get; set; } + + public Vector3d assignedPositionWorld + { + get + { + return VectorUtils.GetWorldSurfacePostion(assignedPositionGeo, vessel.mainBody); + } + protected set + { + assignedPositionGeo = VectorUtils.WorldPositionToGeoCoords(value, vessel.mainBody); + } + } + + //wing commander + public ModuleWingCommander commandLeader { get; protected set; } + + protected PilotCommands command; + public string currentStatus { get; protected set; } = "Free"; + protected int commandFollowIndex; + + public PilotCommands currentCommand => command; + public virtual Vector3d commandGPS => assignedPositionGeo; + + #endregion declarations + + public abstract bool CanEngage(); + + public abstract bool IsValidFixedWeaponTarget(Vessel target); + + /// + /// This will be called every update and should run the autopilot logic. + /// + /// For simple use cases: + /// 1. Engage your target (get in position to engage, shooting is done by guard mode) + /// 2. If no target, check command, and follow it + /// Do this by setting s.pitch, s.yaw and s.roll. + /// + /// For advanced use cases you probably know what you're doing :P + /// + /// current flight control state + protected abstract void AutoPilot(FlightCtrlState s); + + // A small wrapper to make sure the autopilot does not do anything when it shouldn't + private void autoPilot(FlightCtrlState s) + { + if (!weaponManager || !vessel || !vessel.transform || vessel.packed || !vessel.mainBody) + return; + + debugString.Length = 0; + + // generally other AI and guard mode expects this target to be engaged + GetGuardTarget(); // get the guard target from weapon manager + GetNonGuardTarget(); // if guard mode is off, get the UI target + GetGuardNonTarget(); // pick a target if guard mode is on, but no target is selected, + // though really targeting should be managed by the weaponManager, what if we pick an airplane while having only abrams cannons? :P + // (this is another reason why target selection is hardcoded into the base class, so changing this later is less of a mess :) ) + + AutoPilot(s); + } + + #region Pilot on/off + + public virtual void ActivatePilot() + { + pilotOn = true; + if (activeVessel) + activeVessel.OnFlyByWire -= autoPilot; + activeVessel = vessel; + activeVessel.OnFlyByWire += autoPilot; + + if (!speedController) + { + speedController = gameObject.AddComponent(); + speedController.vessel = vessel; + } + + speedController.Activate(); + + GameEvents.onVesselDestroy.Remove(RemoveAutopilot); + GameEvents.onVesselDestroy.Add(RemoveAutopilot); + + assignedPositionWorld = vessel.ReferenceTransform.position; + + RefreshPartWindow(); + } + + public virtual void DeactivatePilot() + { + pilotOn = false; + if (activeVessel) + activeVessel.OnFlyByWire -= autoPilot; + RefreshPartWindow(); + + if (speedController) + { + speedController.Deactivate(); + } + } + + protected void RemoveAutopilot(Vessel v) + { + if (v == vessel) + { + v.OnFlyByWire -= autoPilot; + } + } + + protected void RefreshPartWindow() + { + Events["TogglePilot"].guiName = pilotEnabled ? Localizer.Format("#LOC_BDArmory_DeactivatePilot") : Localizer.Format("#LOC_BDArmory_ActivatePilot");//"Deactivate Pilot""Activate Pilot" + } + + [KSPEvent(guiActive = true, guiName = "#LOC_BDArmory_TogglePilot", active = true)]//Toggle Pilot + public void TogglePilot() + { + if (pilotEnabled) + { + DeactivatePilot(); + } + else + { + ActivatePilot(); + } + } + + [KSPAction("Activate Pilot")] + public void AGActivatePilot(KSPActionParam param) => ActivatePilot(); + + [KSPAction("Deactivate Pilot")] + public void AGDeactivatePilot(KSPActionParam param) => DeactivatePilot(); + + [KSPAction("Toggle Pilot")] + public void AGTogglePilot(KSPActionParam param) => TogglePilot(); + + public virtual string Name { get; } = "AI Control"; + public bool Enabled => pilotEnabled; + + public void Toggle() => TogglePilot(); + + #endregion Pilot on/off + + #region events + + protected virtual void Start() + { + if (HighLogic.LoadedSceneIsFlight) + { + part.OnJustAboutToBeDestroyed += DeactivatePilot; + vessel.OnJustAboutToBeDestroyed += DeactivatePilot; + GameEvents.onVesselWasModified.Add(onVesselWasModified); + MissileFire.OnChangeTeam += OnToggleTeam; + + activeVessel = vessel; + UpdateWeaponManager(); + + if (pilotEnabled) + { + ActivatePilot(); + } + } + + RefreshPartWindow(); + } + + protected virtual void OnDestroy() + { + MissileFire.OnChangeTeam -= OnToggleTeam; + } + + protected virtual void OnGUI() + { + if (!pilotEnabled || !vessel.isActiveVessel) return; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + GUI.Label(new Rect(200, Screen.height - 200, 400, 400), $"{vessel.name}: {debugString.ToString()}"); + } + } + + protected virtual void OnToggleTeam(MissileFire mf, BDTeam team) + { + if (mf.vessel == vessel || (commandLeader && commandLeader.vessel == mf.vessel)) + { + ReleaseCommand(); + } + } + + protected virtual void onVesselWasModified(Vessel v) + { + if (v != activeVessel) + return; + + if (vessel != activeVessel) + { + if (activeVessel) + activeVessel.OnJustAboutToBeDestroyed -= DeactivatePilot; + if (vessel) + vessel.OnJustAboutToBeDestroyed += DeactivatePilot; + if (weaponManager != null && weaponManager.vessel == activeVessel) + { + if (this.Equals(weaponManager.AI)) + weaponManager.AI = null; + UpdateWeaponManager(); + } + } + + activeVessel = vessel; + } + + #endregion events + + #region utilities + + protected void UpdateWeaponManager() + { + weaponManager = vessel.FindPartModuleImplementing(); + if (weaponManager != null) + weaponManager.AI = this; + } + + protected void GetGuardTarget() + { + if (weaponManager == null || weaponManager.vessel != vessel) + UpdateWeaponManager(); + if (weaponManager != null && weaponManager.vessel == vessel) + { + if (weaponManager.guardMode && weaponManager.currentTarget != null) + { + targetVessel = weaponManager.currentTarget.Vessel; + } + else + { + targetVessel = null; + } + weaponManager.AI = this; + return; + } + } + + /// + /// If guard mode is set but no target is selected, pick something + /// + protected virtual void GetGuardNonTarget() + { + if (weaponManager && weaponManager.guardMode && !targetVessel) + { + TargetInfo potentialTarget = BDATargetManager.GetLeastEngagedTarget(weaponManager); + if (potentialTarget && potentialTarget.Vessel) + { + targetVessel = potentialTarget.Vessel; + } + } + } + + /// + /// If guard mode off, and UI target is of the opposing team, set it as target + /// + protected void GetNonGuardTarget() + { + if (weaponManager != null && !weaponManager.guardMode) + { + if (weaponManager.Team.IsEnemy(vessel.targetObject?.GetVessel()?.FindPartModuleImplementing()?.Team)) + targetVessel = (Vessel)vessel.targetObject; + } + } + + /// + /// Write some text to the debug field (the one on lower left when debug labels are on), followed by a newline. + /// + /// text to write + protected void DebugLine(string text) + { + debugString.Append(text); + debugString.Append(Environment.NewLine); + } + + protected void SetStatus(string text) + { + currentStatus = text; + DebugLine(text); + } + + #endregion utilities + + #region WingCommander + + public virtual void ReleaseCommand() + { + if (!vessel || command == PilotCommands.Free) return; + if (command == PilotCommands.Follow && commandLeader) + { + commandLeader = null; + } + Debug.Log(vessel.vesselName + " was released from command."); + command = PilotCommands.Free; + + assignedPositionWorld = vesselTransform.position; + } + + public virtual void CommandFollow(ModuleWingCommander leader, int followerIndex) + { + if (!pilotEnabled) return; + if (leader == vessel || followerIndex < 0) return; + + Debug.Log(vessel.vesselName + " was commanded to follow."); + command = PilotCommands.Follow; + commandLeader = leader; + commandFollowIndex = followerIndex; + } + + public virtual void CommandAG(KSPActionGroup ag) + { + if (!pilotEnabled) return; + vessel.ActionGroups.ToggleGroup(ag); + } + + public virtual void CommandFlyTo(Vector3 gpsCoords) + { + if (!pilotEnabled) return; + + Debug.Log(vessel.vesselName + " was commanded to go to."); + assignedPositionGeo = gpsCoords; + command = PilotCommands.FlyTo; + } + + public virtual void CommandAttack(Vector3 gpsCoords) + { + if (!pilotEnabled) return; + + Debug.Log(vessel.vesselName + " was commanded to attack."); + assignedPositionGeo = gpsCoords; + command = PilotCommands.Attack; + } + + public virtual void CommandTakeOff() + { + ActivatePilot(); + } + + #endregion WingCommander + } +} diff --git a/BDArmory/Modules/BDMMLauncher.cs b/BDArmory/Modules/BDMMLauncher.cs new file mode 100644 index 000000000..e7ba91c33 --- /dev/null +++ b/BDArmory/Modules/BDMMLauncher.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace BDArmory.Modules +{ + public class BDMMLauncher : PartModule + { + public override void OnStart(StartState state) + { + part.force_activate(); + } + + [KSPEvent(name = "Fire", guiActive = true, active = true)] + public void Fire() + { + GameObject target = null; + if (vessel.targetObject != null) target = vessel.targetObject.GetVessel().gameObject; + + part.decouple(0); + + foreach (BDModularGuidance bdmm in vessel.FindPartModulesImplementing()) + { + bdmm.HasFired = true; + //bdmm.target = target; + } + foreach (BDExplosivePart bde in vessel.FindPartModulesImplementing()) + { + //bde.target = target; + } + } + } +} diff --git a/BDArmory/Modules/BDModularGuidance.cs b/BDArmory/Modules/BDModularGuidance.cs new file mode 100644 index 000000000..d9c0cd22c --- /dev/null +++ b/BDArmory/Modules/BDModularGuidance.cs @@ -0,0 +1,1352 @@ +using System; +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Guidances; +using BDArmory.Misc; +using BDArmory.Radar; +using BDArmory.UI; +using KSP.UI.Screens; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class BDModularGuidance : MissileBase + { + private bool _missileIgnited; + private int _nextStage = 1; + + private PartModule _targetDecoupler; + + private readonly Vessel _targetVessel = new Vessel(); + + private Transform _velocityTransform; + + public Vessel LegacyTargetVessel; + + private readonly List _vesselParts = new List(); + + #region KSP FIELDS + + [KSPField] + public string ForwardTransform = "ForwardNegative"; + + [KSPField] + public string UpTransform = "RightPositive"; + + [KSPField(isPersistant = true, guiActive = true, guiName = "#LOC_BDArmory_WeaponName", guiActiveEditor = true), UI_Label(affectSymCounterparts = UI_Scene.All, scene = UI_Scene.All)]//Weapon Name + public string WeaponName; + + [KSPField(isPersistant = false, guiActive = true, guiName = "#LOC_BDArmory_GuidanceType", guiActiveEditor = true)]//Guidance Type + public string GuidanceLabel = "AGM/STS"; + + [KSPField(isPersistant = true, guiActive = true, guiName = "#LOC_BDArmory_TargetingMode", guiActiveEditor = true), UI_Label(affectSymCounterparts = UI_Scene.All, scene = UI_Scene.All)]//Targeting Mode + private string _targetingLabel = TargetingModes.Radar.ToString(); + + [KSPField(isPersistant = true)] + public int GuidanceIndex = 2; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_ActiveRadarRange"), UI_FloatRange(minValue = 6000f, maxValue = 50000f, stepIncrement = 1000f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Active Radar Range + public float ActiveRadarRange = 6000; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerLimiter"), UI_FloatRange(minValue = .1f, maxValue = 1f, stepIncrement = .05f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Steer Limiter + public float MaxSteer = 1; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_StagesNumber"), UI_FloatRange(minValue = 1f, maxValue = 9f, stepIncrement = 1f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Stages Number + public float StagesNumber = 1; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_StageToTriggerOnProximity"), UI_FloatRange(minValue = 0f, maxValue = 6f, stepIncrement = 1f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Stage to Trigger On Proximity + public float StageToTriggerOnProximity = 0; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerDamping"), UI_FloatRange(minValue = 0f, maxValue = 20f, stepIncrement = .05f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Steer Damping + public float SteerDamping = 5; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerFactor"), UI_FloatRange(minValue = 0.1f, maxValue = 20f, stepIncrement = .1f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Steer Factor + public float SteerMult = 10; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_RollCorrection"), UI_Toggle(controlEnabled = true, enabledText = "#LOC_BDArmory_RollCorrection_enabledText", disabledText = "#LOC_BDArmory_RollCorrection_disabledText", scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Roll Correction--Roll enabled--Roll disabled + public bool RollCorrection = false; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_TimeBetweenStages"),//Time Between Stages + UI_FloatRange(minValue = 0f, maxValue = 5f, stepIncrement = 0.5f, scene = UI_Scene.Editor)] + public float timeBetweenStages = 1f; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_MinSpeedGuidance"),//Min Speed before guidance + UI_FloatRange(minValue = 0f, maxValue = 1000f, stepIncrement = 50f, scene = UI_Scene.Editor)] + public float MinSpeedGuidance = 200f; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_ClearanceRadius", advancedTweakable = true),//Clearance radius + UI_FloatRange(minValue = 0f, maxValue = 5f, stepIncrement = 0.05f, scene = UI_Scene.Editor)] + public float clearanceRadius = 0.14f; + + public override float ClearanceRadius => clearanceRadius; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_ClearanceLength", advancedTweakable = true),//Clearance length + UI_FloatRange(minValue = 0f, maxValue = 5f, stepIncrement = 0.05f, scene = UI_Scene.Editor)] + public float clearanceLength = 0.14f; + + public override float ClearanceLength => clearanceLength; + + private Vector3 initialMissileRollPlane; + private Vector3 initialMissileForward; + + + private bool _minSpeedAchieved = false; + private double lastRollAngle; + private double angularVelocity; + + + #endregion KSP FIELDS + + public TransformAxisVectors ForwardTransformAxis { get; set; } + public TransformAxisVectors UpTransformAxis { get; set; } + + public float Mass => (float)vessel.totalMass; + + public enum TransformAxisVectors + { + UpPositive, + UpNegative, + ForwardPositive, + ForwardNegative, + RightPositive, + RightNegative + } + + private void RefreshGuidanceMode() + { + switch (GuidanceIndex) + { + case 1: + GuidanceMode = GuidanceModes.AAMPure; + GuidanceLabel = "AAM"; + break; + + case 2: + GuidanceMode = GuidanceModes.AGM; + GuidanceLabel = "AGM/STS"; + break; + + case 3: + GuidanceMode = GuidanceModes.Cruise; + GuidanceLabel = "Cruise"; + break; + + case 4: + GuidanceMode = GuidanceModes.AGMBallistic; + GuidanceLabel = "Ballistic"; + break; + } + + if (Fields["CruiseAltitude"] != null) + { + CruiseAltitudeRange(); + Fields["CruiseAltitude"].guiActive = GuidanceMode == GuidanceModes.Cruise; + Fields["CruiseAltitude"].guiActiveEditor = GuidanceMode == GuidanceModes.Cruise; + Fields["CruiseSpeed"].guiActive = GuidanceMode == GuidanceModes.Cruise; + Fields["CruiseSpeed"].guiActiveEditor = GuidanceMode == GuidanceModes.Cruise; + Events["CruiseAltitudeRange"].guiActive = GuidanceMode == GuidanceModes.Cruise; + Events["CruiseAltitudeRange"].guiActiveEditor = GuidanceMode == GuidanceModes.Cruise; + Fields["CruisePredictionTime"].guiActiveEditor = GuidanceMode == GuidanceModes.Cruise; + } + + if (Fields["BallisticOverShootFactor"] != null) + { + Fields["BallisticOverShootFactor"].guiActive = GuidanceMode == GuidanceModes.AGMBallistic; + Fields["BallisticOverShootFactor"].guiActiveEditor = GuidanceMode == GuidanceModes.AGMBallistic; + Fields["BallisticAngle"].guiActive = GuidanceMode == GuidanceModes.AGMBallistic; + Fields["BallisticAngle"].guiActiveEditor = GuidanceMode == GuidanceModes.AGMBallistic; + } + if (Fields["SoftAscent"] != null) + { + Fields["SoftAscent"].guiActive = GuidanceMode == GuidanceModes.AGMBallistic; + Fields["SoftAscent"].guiActiveEditor = GuidanceMode == GuidanceModes.AGMBallistic; + } + Misc.Misc.RefreshAssociatedWindows(part); + } + + public override void OnFixedUpdate() + { + if (HasFired && !HasExploded) + { + UpdateGuidance(); + CheckDetonationState(); + CheckDetonationDistance(); + CheckDelayedFired(); + CheckNextStage(); + + if (isTimed && TimeIndex > detonationTime) + { + AutoDestruction(); + } + } + + if (HasExploded && StageToTriggerOnProximity == 0) + { + AutoDestruction(); + } + } + + void Update() + { + CheckDetonationState(); + } + + private void CheckNextStage() + { + if (ShouldExecuteNextStage()) + { + if (!nextStageCountdownStart) + { + this.nextStageCountdownStart = true; + this.stageCutOfftime = Time.time; + } + else + { + if ((Time.time - stageCutOfftime) >= timeBetweenStages) + { + ExecuteNextStage(); + nextStageCountdownStart = false; + } + } + } + } + + public bool nextStageCountdownStart { get; set; } = false; + + public float stageCutOfftime { get; set; } = 0f; + + private void CheckDelayedFired() + { + if (_missileIgnited) return; + if (TimeIndex > dropTime) + { + MissileIgnition(); + } + } + + private void DisableRecursiveFlow(List children) + { + List.Enumerator child = children.GetEnumerator(); + while (child.MoveNext()) + { + if (child.Current == null) continue; + + DisablingExplosives(child.Current); + + IEnumerator resource = child.Current.Resources.GetEnumerator(); + while (resource.MoveNext()) + { + if (resource.Current == null) continue; + if (resource.Current.flowState) + { + resource.Current.flowState = false; + } + } + resource.Dispose(); + + if (child.Current.children.Count > 0) + { + DisableRecursiveFlow(child.Current.children); + } + if (!_vesselParts.Contains(child.Current)) _vesselParts.Add(child.Current); + } + child.Dispose(); + } + + private void EnableResourceFlow(List children) + { + List.Enumerator child = children.GetEnumerator(); + while (child.MoveNext()) + { + if (child.Current == null) continue; + + SetupExplosive(child.Current); + + IEnumerator resource = child.Current.Resources.GetEnumerator(); + while (resource.MoveNext()) + { + if (resource.Current == null) continue; + if (!resource.Current.flowState) + { + resource.Current.flowState = true; + } + } + resource.Dispose(); + if (child.Current.children.Count > 0) + { + EnableResourceFlow(child.Current.children); + } + } + child.Dispose(); + } + + private void DisableResourcesFlow() + { + if (_targetDecoupler != null) + { + if (_targetDecoupler.part.children.Count == 0) return; + _vesselParts.Clear(); + DisableRecursiveFlow(_targetDecoupler.part.children); + } + } + + private void MissileIgnition() + { + EnableResourceFlow(_vesselParts); + GameObject velocityObject = new GameObject("velObject"); + velocityObject.transform.position = vessel.transform.position; + velocityObject.transform.parent = vessel.transform; + _velocityTransform = velocityObject.transform; + + MissileState = MissileStates.Boost; + + ExecuteNextStage(); + + MissileState = MissileStates.Cruise; + + _missileIgnited = true; + RadarWarningReceiver.WarnMissileLaunch(MissileReferenceTransform.position, GetForwardTransform()); + } + + private bool ShouldExecuteNextStage() + { + if (!_missileIgnited) return false; + if (TimeIndex < 1) return false; + + // Replaced Linq expression... + List.Enumerator parts = vessel.parts.GetEnumerator(); + + while (parts.MoveNext()) + { + if (parts.Current == null || !IsEngine(parts.Current)) continue; + if (EngineIgnitedAndHasFuel(parts.Current)) + { + return false; + } + } + parts.Dispose(); + + //If the next stage is greater than the number defined of stages the missile is done + if (_nextStage > StagesNumber) + { + MissileState = MissileStates.PostThrust; + return false; + } + + return true; + } + + public bool IsEngine(Part p) + { + List.Enumerator m = p.Modules.GetEnumerator(); + while (m.MoveNext()) + { + if (m.Current == null) continue; + if (m.Current is ModuleEngines) return true; + } + m.Dispose(); + return false; + } + + public static bool EngineIgnitedAndHasFuel(Part p) + { + List.Enumerator m = p.Modules.GetEnumerator(); + + while (m.MoveNext()) + { + PartModule pm = m.Current; + ModuleEngines eng = pm as ModuleEngines; + if (eng != null) + { + return (eng.EngineIgnited && (!eng.getFlameoutState || eng.flameoutBar == 0 || eng.status == "Nominal")); + } + } + m.Dispose(); + return false; + } + + public override void OnStart(StartState state) + { + base.OnStart(state); + SetupsFields(); + + if (string.IsNullOrEmpty(GetShortName())) + { + shortName = "Unnamed"; + } + part.force_activate(); + RefreshGuidanceMode(); + + UpdateTargetingMode((TargetingModes)Enum.Parse(typeof(TargetingModes), _targetingLabel)); + + _targetDecoupler = FindFirstDecoupler(part.parent, null); + + DisableResourcesFlow(); + + weaponClass = WeaponClasses.Missile; + WeaponName = GetShortName(); + + activeRadarRange = ActiveRadarRange; + + //TODO: BDModularGuidance should be configurable? + heatThreshold = 50; + lockedSensorFOV = 5; + radarLOAL = true; + + // fill activeRadarLockTrackCurve with default values if not set by part config: + if ((TargetingMode == TargetingModes.Radar || TargetingModeTerminal == TargetingModes.Radar) && activeRadarRange > 0 && activeRadarLockTrackCurve.minTime == float.MaxValue) + { + activeRadarLockTrackCurve.Add(0f, 0f); + activeRadarLockTrackCurve.Add(activeRadarRange, RadarUtils.MISSILE_DEFAULT_LOCKABLE_RCS); // TODO: tune & balance constants! + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: OnStart missile " + shortName + ": setting default locktrackcurve with maxrange/minrcs: " + activeRadarLockTrackCurve.maxTime + "/" + RadarUtils.MISSILE_DEFAULT_LOCKABLE_RCS); + } + + } + + private void SetupsFields() + { + Events["HideUI"].active = false; + Events["ShowUI"].active = true; + + if (isTimed) + { + Fields["detonationTime"].guiActive = true; + Fields["detonationTime"].guiActiveEditor = true; + } + else + { + Fields["detonationTime"].guiActive = false; + Fields["detonationTime"].guiActiveEditor = false; + } + + if (HighLogic.LoadedSceneIsEditor) + { + WeaponNameWindow.OnActionGroupEditorOpened.Add(OnActionGroupEditorOpened); + WeaponNameWindow.OnActionGroupEditorClosed.Add(OnActionGroupEditorClosed); + Fields["CruiseAltitude"].guiActiveEditor = true; + Fields["CruiseSpeed"].guiActiveEditor = false; + Events["SwitchTargetingMode"].guiActiveEditor = true; + Events["SwitchGuidanceMode"].guiActiveEditor = true; + } + else + { + Fields["CruiseAltitude"].guiActiveEditor = false; + Fields["CruiseSpeed"].guiActiveEditor = false; + Events["SwitchTargetingMode"].guiActiveEditor = false; + Events["SwitchGuidanceMode"].guiActiveEditor = false; + SetMissileTransform(); + } + + UI_FloatRange staticMin = (UI_FloatRange)Fields["minStaticLaunchRange"].uiControlEditor; + UI_FloatRange staticMax = (UI_FloatRange)Fields["maxStaticLaunchRange"].uiControlEditor; + UI_FloatRange radarMax = (UI_FloatRange)Fields["ActiveRadarRange"].uiControlEditor; + + staticMin.onFieldChanged += OnStaticRangeUpdated; + staticMax.onFieldChanged += OnStaticRangeUpdated; + staticMax.maxValue = BDArmorySettings.MAX_ENGAGEMENT_RANGE; + staticMax.stepIncrement = BDArmorySettings.MAX_ENGAGEMENT_RANGE / 100; + radarMax.maxValue = BDArmorySettings.MAX_ENGAGEMENT_RANGE; + radarMax.stepIncrement = BDArmorySettings.MAX_ENGAGEMENT_RANGE / 100; + + UI_FloatRange stageOnProximity = (UI_FloatRange)Fields["StageToTriggerOnProximity"].uiControlEditor; + stageOnProximity.onFieldChanged = OnStageOnProximity; + + OnStageOnProximity(Fields["StageToTriggerOnProximity"], null); + InitializeEngagementRange(minStaticLaunchRange, maxStaticLaunchRange); + } + + private void OnStageOnProximity(BaseField baseField, object o) + { + UI_FloatRange detonationDistance = (UI_FloatRange)Fields["DetonationDistance"].uiControlEditor; + + if (StageToTriggerOnProximity != 0) + { + detonationDistance = (UI_FloatRange)Fields["DetonationDistance"].uiControlEditor; + + detonationDistance.maxValue = 8000; + + detonationDistance.stepIncrement = 50; + } + else + { + detonationDistance.maxValue = 100; + + detonationDistance.stepIncrement = 1; + } + } + + private void OnStaticRangeUpdated(BaseField baseField, object o) + { + InitializeEngagementRange(minStaticLaunchRange, maxStaticLaunchRange); + } + + private void UpdateTargetingMode(TargetingModes newTargetingMode) + { + if (newTargetingMode == TargetingModes.Radar) + { + Fields["ActiveRadarRange"].guiActive = true; + Fields["ActiveRadarRange"].guiActiveEditor = true; + } + else + { + Fields["ActiveRadarRange"].guiActive = false; + Fields["ActiveRadarRange"].guiActiveEditor = false; + } + TargetingMode = newTargetingMode; + _targetingLabel = newTargetingMode.ToString(); + + Misc.Misc.RefreshAssociatedWindows(part); + } + + private void OnDestroy() + { + WeaponNameWindow.OnActionGroupEditorOpened.Remove(OnActionGroupEditorOpened); + WeaponNameWindow.OnActionGroupEditorClosed.Remove(OnActionGroupEditorClosed); + GameEvents.onPartDie.Remove(PartDie); + } + + private void SetMissileTransform() + { + MissileReferenceTransform = part.transform; + ForwardTransformAxis = (TransformAxisVectors)Enum.Parse(typeof(TransformAxisVectors), ForwardTransform); + UpTransformAxis = (TransformAxisVectors)Enum.Parse(typeof(TransformAxisVectors), UpTransform); + } + + void UpdateGuidance() + { + if (guidanceActive) + { + switch (TargetingMode) + { + case TargetingModes.None: + if (_targetVessel != null) + { + TargetPosition = _targetVessel.CurrentCoM; + TargetVelocity = _targetVessel.Velocity(); + TargetAcceleration = _targetVessel.acceleration; + } + break; + + case TargetingModes.Radar: + UpdateRadarTarget(); + break; + + case TargetingModes.Heat: + UpdateHeatTarget(); + break; + + case TargetingModes.Laser: + UpdateLaserTarget(); + break; + + case TargetingModes.Gps: + UpdateGPSTarget(); + break; + + case TargetingModes.AntiRad: + UpdateAntiRadiationTarget(); + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + private Vector3 AAMGuidance() + { + Vector3 aamTarget; + if (TargetAcquired) + { + float timeToImpact; + aamTarget = MissileGuidance.GetAirToAirTargetModular(TargetPosition, TargetVelocity, TargetAcceleration, vessel, out timeToImpact); + TimeToImpact = timeToImpact; + if (Vector3.Angle(aamTarget - vessel.CoM, vessel.transform.forward) > maxOffBoresight * 0.75f) + { + Debug.LogFormat("[BDArmory]: Missile with Name={0} has exceeded the max off boresight, checking missed target ", vessel.vesselName); + aamTarget = TargetPosition; + } + DrawDebugLine(vessel.CoM, aamTarget); + } + else + { + aamTarget = vessel.CoM + (20 * vessel.srfSpeed * vessel.Velocity().normalized); + } + + return aamTarget; + } + + private Vector3 AGMGuidance() + { + if (TargetingMode != TargetingModes.Gps) + { + if (TargetAcquired) + { + //lose lock if seeker reaches gimbal limit + float targetViewAngle = Vector3.Angle(vessel.transform.forward, TargetPosition - vessel.CoM); + + if (targetViewAngle > maxOffBoresight) + { + Debug.Log("[BDArmory]: AGM Missile guidance failed - target out of view"); + guidanceActive = false; + } + } + else + { + if (TargetingMode == TargetingModes.Laser) + { + //keep going straight until found laser point + TargetPosition = laserStartPosition + (20000 * startDirection); + } + } + } + Vector3 agmTarget = MissileGuidance.GetAirToGroundTarget(TargetPosition, vessel, 1.85f); + return agmTarget; + } + + private Vector3 CruiseGuidance() + { + if (this._guidance == null) + { + this._guidance = new CruiseGuidance(this); + } + + return this._guidance.GetDirection(this,TargetPosition); + } + + private void CheckMiss(Vector3 targetPosition) + { + if (HasMissed) return; + // if I'm to close to my vessel avoid explosion + if ((vessel.CoM - SourceVessel.CoM).magnitude < 4 * DetonationDistance) return; + // if I'm getting closer to my target avoid explosion + if ((vessel.CoM - targetPosition).sqrMagnitude > + (vessel.CoM + (vessel.Velocity() * Time.fixedDeltaTime) - (targetPosition + (TargetVelocity * Time.fixedDeltaTime))).sqrMagnitude) return; + + if (MissileState != MissileStates.PostThrust ) return; + + Debug.Log("[BDArmory]: Missile CheckMiss showed miss"); + HasMissed = true; + guidanceActive = false; + TargetMf = null; + isTimed = true; + detonationTime = TimeIndex + 1.5f; + } + + private void CheckMiss() + { + if (HasMissed) return; + + + if (MissileState == MissileStates.PostThrust && (vessel.LandedOrSplashed || vessel.Velocity().magnitude < 10f)) + { + Debug.Log("[BDArmory]: Missile CheckMiss showed miss"); + HasMissed = true; + guidanceActive = false; + TargetMf = null; + isTimed = true; + detonationTime = TimeIndex + 1.5f; + } + } + + + public void GuidanceSteer(FlightCtrlState s) + { + debugString.Length = 0; + if (guidanceActive && MissileReferenceTransform != null && _velocityTransform != null) + { + if (vessel.Velocity().magnitude < MinSpeedGuidance) + { + if (!_minSpeedAchieved) + { + s.mainThrottle = 1; + return; + } + } + else + { + _minSpeedAchieved = true; + } + + Vector3 newTargetPosition = new Vector3(); + switch (GuidanceIndex) + { + case 1: + newTargetPosition = AAMGuidance(); + break; + + case 2: + newTargetPosition = AGMGuidance(); + break; + + case 3: + newTargetPosition = CruiseGuidance(); + break; + + case 4: + newTargetPosition = BallisticGuidance(); + break; + } + CheckMiss(newTargetPosition); + + //Updating aero surfaces + if (TimeIndex > dropTime + 0.5f) + { + _velocityTransform.rotation = Quaternion.LookRotation(vessel.Velocity(), -vessel.transform.forward); + Vector3 targetDirection = _velocityTransform.InverseTransformPoint(newTargetPosition).normalized; + targetDirection = Vector3.RotateTowards(Vector3.forward, targetDirection, 15 * Mathf.Deg2Rad, 0); + + Vector3 localAngVel = vessel.angularVelocity; + float steerYaw = SteerMult * targetDirection.x - SteerDamping * -localAngVel.z; + float steerPitch = SteerMult * targetDirection.y - SteerDamping * -localAngVel.x; + + s.yaw = Mathf.Clamp(steerYaw, -MaxSteer, MaxSteer); + s.pitch = Mathf.Clamp(steerPitch, -MaxSteer, MaxSteer); + + if (RollCorrection) + { + SetRoll(); + s.roll = Roll; + } + } + s.mainThrottle = Throttle; + } + + CheckMiss(); + } + + private void SetRoll() + { + var vesselTransform = vessel.transform.position; + + Vector3 gravityVector = FlightGlobals.getGeeForceAtPosition(vesselTransform).normalized; + Vector3 rollVessel = -vessel.transform.right.normalized; + + var currentAngle = Vector3.SignedAngle(rollVessel, gravityVector, Vector3.Cross(rollVessel, gravityVector)) - 90f; + + debugString.Append($"Roll angle: {currentAngle}"); + debugString.Append(Environment.NewLine); + this.angularVelocity = currentAngle - this.lastRollAngle; + //this.angularAcceleration = angularVelocity - this.lasAngularVelocity; + + var futureAngle = currentAngle + angularVelocity / Time.fixedDeltaTime * 1f; + + debugString.Append($"future Roll angle: {futureAngle}"); + + if (futureAngle > 0.5f || currentAngle > 0.5f) + { + this.Roll = Mathf.Clamp(Roll - 0.001f, -1f, 0f); + } + else if (futureAngle < -0.5f || currentAngle < -0.5f) + { + this.Roll = Mathf.Clamp(Roll + 0.001f, 0, 1f); + } + debugString.Append($"Roll value: {this.Roll}"); + + lastRollAngle = currentAngle; + //lasAngularVelocity = angularVelocity; + } + + public float Roll { get; set; } + + private Vector3 BallisticGuidance() + { + return CalculateAGMBallisticGuidance(this, TargetPosition); + } + + private void UpdateMenus(bool visible) + { + Events["HideUI"].active = visible; + Events["ShowUI"].active = !visible; + } + + private void OnActionGroupEditorOpened() + { + Events["HideUI"].active = false; + Events["ShowUI"].active = false; + } + + private void OnActionGroupEditorClosed() + { + Events["HideUI"].active = false; + Events["ShowUI"].active = true; + } + + /// + /// Recursive method to find the top decoupler that should be used to jettison the missile. + /// + /// + /// + /// + private PartModule FindFirstDecoupler(Part parent, PartModule last) + { + if (parent == null || !parent) return last; + + PartModule newModuleDecouple = parent.FindModuleImplementing(); + if (newModuleDecouple == null) + { + newModuleDecouple = parent.FindModuleImplementing(); + } + if (newModuleDecouple != null && newModuleDecouple) + { + return FindFirstDecoupler(parent.parent, newModuleDecouple); + } + return FindFirstDecoupler(parent.parent, last); + } + + /// + /// This method will execute the next ActionGroup. Due to StageManager is designed to work with an active vessel + /// And a missile is not an active vessel. I had to use a different way handle stages. And action groups works perfect! + /// + public void ExecuteNextStage() + { + Debug.LogFormat("[BDArmory]: BDModularGuidance - executing next stage {0}", _nextStage); + vessel.ActionGroups.ToggleGroup( + (KSPActionGroup)Enum.Parse(typeof(KSPActionGroup), "Custom0" + (int)_nextStage)); + + _nextStage++; + + vessel.OnFlyByWire += GuidanceSteer; + + //todo: find a way to fly by wire vessel decoupled + } + + void OnGUI() + { + if (HighLogic.LoadedSceneIsFlight) + { + drawLabels(); + } + } + + #region KSP ACTIONS + + [KSPAction("Fire Missile")] + public void AgFire(KSPActionParam param) + { + FireMissile(); + } + + #endregion KSP ACTIONS + + #region KSP EVENTS + + [KSPEvent(guiActive = true, guiName = "#LOC_BDArmory_FireMissile", active = true)]//Fire Missile + public void GuiFire() + { + FireMissile(); + } + + [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_FireMissile", active = true)]//Fire Missile + public override void FireMissile() + { + if (BDArmorySetup.Instance.ActiveWeaponManager != null && + BDArmorySetup.Instance.ActiveWeaponManager.vessel == vessel) + { + BDArmorySetup.Instance.ActiveWeaponManager.SendTargetDataToMissile(this); + } + + if (!HasFired) + { + GameEvents.onPartDie.Add(PartDie); + BDATargetManager.FiredMissiles.Add(this); + + List.Enumerator wpm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (wpm.MoveNext()) + { + if (wpm.Current == null) continue; + Team = wpm.Current.Team; + break; + } + wpm.Dispose(); + + SourceVessel = vessel; + SetTargeting(); + Jettison(); + AddTargetInfoToVessel(); + IncreaseTolerance(); + + this.initialMissileRollPlane = -this.vessel.transform.up; + this.initialMissileForward = this.vessel.transform.forward; + vessel.vesselName = GetShortName(); + vessel.vesselType = VesselType.Plane; + + if (!vessel.ActionGroups[KSPActionGroup.SAS]) + { + vessel.ActionGroups.ToggleGroup(KSPActionGroup.SAS); + } + + TimeFired = Time.time; + MissileState = MissileStates.Drop; + + Misc.Misc.RefreshAssociatedWindows(part); + + HasFired = true; + DetonationDistanceState = DetonationDistanceStates.NotSafe; + } + if (BDArmorySetup.Instance.ActiveWeaponManager != null) + { + BDArmorySetup.Instance.ActiveWeaponManager.UpdateList(); + } + } + + private void IncreaseTolerance() + { + foreach (var vesselPart in this.vessel.parts) + { + vesselPart.crashTolerance = 99; + vesselPart.breakingForce = 99; + vesselPart.breakingTorque = 99; + } + } + + private void SetTargeting() + { + startDirection = GetForwardTransform(); + SetLaserTargeting(); + SetAntiRadTargeting(); + } + + void OnDisable() + { + if (TargetingMode == TargetingModes.AntiRad) + { + RadarWarningReceiver.OnRadarPing -= ReceiveRadarPing; + } + } + + public Vector3 StartDirection { get; set; } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_GuidanceMode", active = true)]//Guidance Mode + public void SwitchGuidanceMode() + { + GuidanceIndex++; + if (GuidanceIndex > 4) + { + GuidanceIndex = 1; + } + + RefreshGuidanceMode(); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_TargetingMode", active = true)]//Targeting Mode + public void SwitchTargetingMode() + { + string[] targetingModes = Enum.GetNames(typeof(TargetingModes)); + + int currentIndex = targetingModes.IndexOf(TargetingMode.ToString()); + + if (currentIndex < targetingModes.Length - 1) + { + UpdateTargetingMode((TargetingModes)Enum.Parse(typeof(TargetingModes), targetingModes[currentIndex + 1])); + } + else + { + UpdateTargetingMode((TargetingModes)Enum.Parse(typeof(TargetingModes), targetingModes[0])); + } + } + + [KSPEvent(guiActive = true, guiActiveEditor = false, active = true, guiName = "#LOC_BDArmory_Jettison")]//Jettison + public override void Jettison() + { + if (_targetDecoupler == null || !_targetDecoupler || !(_targetDecoupler is IStageSeparator)) return; + + ModuleDecouple decouple = _targetDecoupler as ModuleDecouple; + if (decouple != null) + { + decouple.ejectionForce *= 5; + decouple.Decouple(); + } + else + { + ((ModuleAnchoredDecoupler)_targetDecoupler).ejectionForce *= 5; + ((ModuleAnchoredDecoupler)_targetDecoupler).Decouple(); + } + + if (BDArmorySetup.Instance.ActiveWeaponManager != null) + BDArmorySetup.Instance.ActiveWeaponManager.UpdateList(); + } + + public override float GetBlastRadius() + { + if (vessel.FindPartModulesImplementing().Count > 0) + { + return vessel.FindPartModulesImplementing().Max(x => x.blastRadius); + } + else + { + return 5; + } + } + + protected override void PartDie(Part p) + { + if (p != part) return; + AutoDestruction(); + BDATargetManager.FiredMissiles.Remove(this); + GameEvents.onPartDie.Remove(PartDie); + } + + private void AutoDestruction() + { + var parts = this.vessel.Parts.ToArray(); + for (int i = parts.Length - 1; i >= 0; i--) + { + parts[i]?.explode(); + } + + parts = null; + } + + public override void Detonate() + { + if (HasExploded || !HasFired) return; + if (SourceVessel == null) SourceVessel = vessel; + + HasExploded = true; + if (StageToTriggerOnProximity != 0) + { + vessel.ActionGroups.ToggleGroup( + (KSPActionGroup)Enum.Parse(typeof(KSPActionGroup), "Custom0" + (int)StageToTriggerOnProximity)); + } + else + { + vessel.FindPartModulesImplementing().ForEach(explosivePart => explosivePart.DetonateIfPossible()); + AutoDestruction(); + } + } + + public override Vector3 GetForwardTransform() + { + return GetTransform(ForwardTransformAxis); + } + + public Vector3 GetTransform(TransformAxisVectors transformAxis) + { + switch (transformAxis) + { + case TransformAxisVectors.UpPositive: + return MissileReferenceTransform.up; + + case TransformAxisVectors.UpNegative: + return -MissileReferenceTransform.up; + + case TransformAxisVectors.ForwardPositive: + return MissileReferenceTransform.forward; + + case TransformAxisVectors.ForwardNegative: + return -MissileReferenceTransform.forward; + + case TransformAxisVectors.RightNegative: + return -MissileReferenceTransform.right; + + case TransformAxisVectors.RightPositive: + return MissileReferenceTransform.right; + + default: + return MissileReferenceTransform.forward; + } + } + + [KSPEvent(guiActiveEditor = true, guiName = "#LOC_BDArmory_HideUI", active = false)]//Hide Weapon Name UI + public void HideUI() + { + WeaponNameWindow.HideGUI(); + UpdateMenus(false); + } + + [KSPEvent(guiActiveEditor = true, guiName = "#LOC_BDArmory_ShowUI", active = false)]//Set Weapon Name UI + public void ShowUI() + { + WeaponNameWindow.ShowGUI(this); + UpdateMenus(true); + } + + void OnCollisionEnter(Collision col) + { + base.CollisionEnter(col); + } + + #endregion KSP EVENTS + } + + #region UI + + [KSPAddon(KSPAddon.Startup.EditorAny, false)] + public class WeaponNameWindow : MonoBehaviour + { + internal static EventVoid OnActionGroupEditorOpened = new EventVoid("OnActionGroupEditorOpened"); + internal static EventVoid OnActionGroupEditorClosed = new EventVoid("OnActionGroupEditorClosed"); + + private static GUIStyle unchanged; + private static GUIStyle changed; + private static GUIStyle greyed; + private static GUIStyle overfull; + + private static WeaponNameWindow instance; + private static Vector3 mousePos = Vector3.zero; + + private bool ActionGroupMode; + + private Rect guiWindowRect = new Rect(0, 0, 0, 0); + + private BDModularGuidance missile_module; + + [KSPField] public int offsetGUIPos = -1; + + private Vector2 scrollPos; + + [KSPField(isPersistant = false, guiActiveEditor = true, guiActive = false, guiName = "#LOC_BDArmory_RollCorrection_showRFGUI"), UI_Toggle(enabledText = "#LOC_BDArmory_showRFGUI_enabledText", disabledText = "#LOC_BDArmory_showRFGUI_disabledText")] [NonSerialized] public bool showRFGUI;//Show Weapon Name Editor--Weapon Name GUI--GUI + + private bool styleSetup; + + private string txtName = string.Empty; + + public static void HideGUI() + { + if (instance != null && instance.missile_module != null) + { + instance.missile_module.WeaponName = instance.missile_module.shortName; + instance.missile_module = null; + instance.UpdateGUIState(); + } + EditorLogic editor = EditorLogic.fetch; + if (editor != null) + editor.Unlock("BD_MN_GUILock"); + } + + public static void ShowGUI(BDModularGuidance missile_module) + { + if (instance != null) + { + instance.missile_module = missile_module; + instance.UpdateGUIState(); + } + } + + private void UpdateGUIState() + { + enabled = missile_module != null; + EditorLogic editor = EditorLogic.fetch; + if (!enabled && editor != null) + editor.Unlock("BD_MN_GUILock"); + } + + private IEnumerator CheckActionGroupEditor() + { + while (EditorLogic.fetch == null) + { + yield return null; + } + EditorLogic editor = EditorLogic.fetch; + while (EditorLogic.fetch != null) + { + if (editor.editorScreen == EditorScreen.Actions) + { + if (!ActionGroupMode) + { + HideGUI(); + OnActionGroupEditorOpened.Fire(); + } + EditorActionGroups age = EditorActionGroups.Instance; + if (missile_module && !age.GetSelectedParts().Contains(missile_module.part)) + { + HideGUI(); + } + ActionGroupMode = true; + } + else + { + if (ActionGroupMode) + { + HideGUI(); + OnActionGroupEditorClosed.Fire(); + } + ActionGroupMode = false; + } + yield return null; + } + } + + private void Awake() + { + enabled = false; + instance = this; + StartCoroutine(CheckActionGroupEditor()); + } + + private void OnDestroy() + { + instance = null; + } + + public void OnGUI() + { + if (!styleSetup) + { + styleSetup = true; + Styles.InitStyles(); + } + + EditorLogic editor = EditorLogic.fetch; + if (!HighLogic.LoadedSceneIsEditor || !editor) + { + return; + } + bool cursorInGUI = false; // nicked the locking code from Ferram + mousePos = Input.mousePosition; //Mouse location; based on Kerbal Engineer Redux code + mousePos.y = Screen.height - mousePos.y; + + int posMult = 0; + if (offsetGUIPos != -1) + { + posMult = offsetGUIPos; + } + if (ActionGroupMode) + { + if (guiWindowRect.width == 0) + { + guiWindowRect = new Rect(430 * posMult, 365, 438, 50); + } + new Rect(guiWindowRect.xMin + 440, mousePos.y - 5, 300, 20); + } + else + { + if (guiWindowRect.width == 0) + { + //guiWindowRect = new Rect(Screen.width - 8 - 430 * (posMult + 1), 365, 438, (Screen.height - 365)); + guiWindowRect = new Rect(Screen.width - 8 - 430 * (posMult + 1), 365, 438, 50); + } + new Rect(guiWindowRect.xMin - (230 - 8), mousePos.y - 5, 220, 20); + } + cursorInGUI = guiWindowRect.Contains(mousePos); + if (cursorInGUI) + { + editor.Lock(false, false, false, "BD_MN_GUILock"); + //if (EditorTooltip.Instance != null) + // EditorTooltip.Instance.HideToolTip(); + } + else + { + editor.Unlock("BD_MN_GUILock"); + } + guiWindowRect = GUILayout.Window(GetInstanceID(), guiWindowRect, GUIWindow, "Weapon Name GUI", Styles.styleEditorPanel); + } + + public void GUIWindow(int windowID) + { + InitializeStyles(); + + GUILayout.BeginVertical(); + GUILayout.Space(20); + + GUILayout.BeginHorizontal(); + + GUILayout.Label("Weapon Name: "); + + txtName = GUILayout.TextField(txtName); + + if (GUILayout.Button("Save & Close")) + { + missile_module.WeaponName = txtName; + missile_module.shortName = txtName; + instance.missile_module.HideUI(); + } + + GUILayout.EndHorizontal(); + + scrollPos = GUILayout.BeginScrollView(scrollPos); + + GUILayout.EndScrollView(); + + GUILayout.EndVertical(); + + GUI.DragWindow(); + BDGUIUtils.RepositionWindow(ref guiWindowRect); + } + + private static void InitializeStyles() + { + if (unchanged == null) + { + if (GUI.skin == null) + { + unchanged = new GUIStyle(); + changed = new GUIStyle(); + greyed = new GUIStyle(); + overfull = new GUIStyle(); + } + else + { + unchanged = new GUIStyle(GUI.skin.textField); + changed = new GUIStyle(GUI.skin.textField); + greyed = new GUIStyle(GUI.skin.textField); + overfull = new GUIStyle(GUI.skin.label); + } + + unchanged.normal.textColor = Color.white; + unchanged.active.textColor = Color.white; + unchanged.focused.textColor = Color.white; + unchanged.hover.textColor = Color.white; + + changed.normal.textColor = Color.yellow; + changed.active.textColor = Color.yellow; + changed.focused.textColor = Color.yellow; + changed.hover.textColor = Color.yellow; + + greyed.normal.textColor = Color.gray; + + overfull.normal.textColor = Color.red; + } + } + } + + internal class Styles + { + // Base styles + public static GUIStyle styleEditorTooltip; + public static GUIStyle styleEditorPanel; + + /// + /// This one sets up the styles we use + /// + internal static void InitStyles() + { + styleEditorTooltip = new GUIStyle(); + styleEditorTooltip.name = "Tooltip"; + styleEditorTooltip.fontSize = 12; + styleEditorTooltip.normal.textColor = new Color32(207, 207, 207, 255); + styleEditorTooltip.stretchHeight = true; + styleEditorTooltip.wordWrap = true; + styleEditorTooltip.normal.background = CreateColorPixel(new Color32(7, 54, 66, 200)); + styleEditorTooltip.border = new RectOffset(3, 3, 3, 3); + styleEditorTooltip.padding = new RectOffset(4, 4, 6, 4); + styleEditorTooltip.alignment = TextAnchor.MiddleLeft; + + styleEditorPanel = new GUIStyle(); + styleEditorPanel.normal.background = CreateColorPixel(new Color32(7, 54, 66, 200)); + styleEditorPanel.border = new RectOffset(27, 27, 27, 27); + styleEditorPanel.padding = new RectOffset(10, 10, 10, 10); + styleEditorPanel.normal.textColor = new Color32(147, 161, 161, 255); + styleEditorPanel.fontSize = 12; + } + + /// + /// Creates a 1x1 texture + /// + /// Color of the texture + /// + internal static Texture2D CreateColorPixel(Color32 Background) + { + Texture2D retTex = new Texture2D(1, 1); + retTex.SetPixel(0, 0, Background); + retTex.Apply(); + return retTex; + } + } + + #endregion UI +} diff --git a/BDArmory/Modules/BDModulePilotAI.cs b/BDArmory/Modules/BDModulePilotAI.cs new file mode 100644 index 000000000..c624a6a18 --- /dev/null +++ b/BDArmory/Modules/BDModulePilotAI.cs @@ -0,0 +1,1803 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using BDArmory.Control; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Guidances; +using BDArmory.Misc; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class BDModulePilotAI : BDGenericAIBase, IBDAIControl + { + public enum SteerModes { NormalFlight, Aiming } + + SteerModes steerMode = SteerModes.NormalFlight; + + bool belowMinAltitude; + bool extending; + + bool requestedExtend; + Vector3 requestedExtendTpos; + + public bool IsExtending + { + get { return extending || requestedExtend; } + } + + public void RequestExtend(Vector3 tPosition) + { + requestedExtend = true; + requestedExtendTpos = tPosition; + } + + public override bool CanEngage() + { + return !vessel.LandedOrSplashed; + } + + GameObject vobj; + + Transform velocityTransform + { + get + { + if (!vobj) + { + vobj = new GameObject("velObject"); + vobj.transform.position = vessel.ReferenceTransform.position; + vobj.transform.parent = vessel.ReferenceTransform; + } + + return vobj.transform; + } + } + + Vector3 upDirection = Vector3.up; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_DefaultAltitude"),//Default Alt. + UI_FloatRange(minValue = 500f, maxValue = 15000f, stepIncrement = 25f, scene = UI_Scene.All)] + public float defaultAltitude = 1500; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MinAltitude"),//Min Altitude + UI_FloatRange(minValue = 150f, maxValue = 6000, stepIncrement = 50f, scene = UI_Scene.All)] + public float minAltitude = 500f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerFactor"),//Steer Factor + UI_FloatRange(minValue = 0.1f, maxValue = 20f, stepIncrement = .1f, scene = UI_Scene.All)] + public float steerMult = 6; + //make a combat steer mult and idle steer mult + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerKi"),//Steer Ki + UI_FloatRange(minValue = 0.01f, maxValue = 1f, stepIncrement = 0.01f, scene = UI_Scene.All)] + public float steerKiAdjust = 0.05f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_StagesNumber"),//Steer Limiter + UI_FloatRange(minValue = .1f, maxValue = 1f, stepIncrement = .05f, scene = UI_Scene.All)] + public float maxSteer = 1; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerDamping"),//Steer Damping + UI_FloatRange(minValue = 1f, maxValue = 8f, stepIncrement = 0.5f, scene = UI_Scene.All)] + public float steerDamping = 3; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxSpeed"),//Max Speed + UI_FloatRange(minValue = 20f, maxValue = 800f, stepIncrement = 1.0f, scene = UI_Scene.All)] + public float maxSpeed = 325; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_TakeOffSpeed"),//TakeOff Speed + UI_FloatRange(minValue = 10f, maxValue = 200f, stepIncrement = 1.0f, scene = UI_Scene.All)] + public float takeOffSpeed = 70; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MinSpeed"),//MinCombatSpeed + UI_FloatRange(minValue = 20f, maxValue = 200, stepIncrement = 1.0f, scene = UI_Scene.All)] + public float minSpeed = 60f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_IdleSpeed"),//Idle Speed + UI_FloatRange(minValue = 10f, maxValue = 200f, stepIncrement = 1.0f, scene = UI_Scene.All)] + public float idleSpeed = 120f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_maxAllowedGForce"),//Max G + UI_FloatRange(minValue = 2f, maxValue = 45f, stepIncrement = 0.25f, scene = UI_Scene.All)] + public float maxAllowedGForce = 10; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_maxAllowedAoA"),//Max AoA + UI_FloatRange(minValue = 0f, maxValue = 85f, stepIncrement = 2.5f, scene = UI_Scene.All)] + public float maxAllowedAoA = 35; + float maxAllowedCosAoA; + float lastAllowedAoA; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_Orbit", advancedTweakable = true),//Orbit + UI_Toggle(enabledText = "#LOC_BDArmory_Orbit_enabledText", disabledText = "#LOC_BDArmory_Orbit_disabledText", scene = UI_Scene.All),]//Starboard (CW)--Port (CCW) + public bool ClockwiseOrbit = true; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_UnclampTuning", advancedTweakable = true),//Unclamp tuning + UI_Toggle(enabledText = "#LOC_BDArmory_UnclampTuning_enabledText", disabledText = "#LOC_BDArmory_UnclampTuning_disabledText", scene = UI_Scene.All),]//Unclamped--Clamped + public bool UpToEleven = false; + bool toEleven = false; + + Dictionary altMaxValues = new Dictionary + { + { nameof(defaultAltitude), 100000f }, + { nameof(minAltitude), 30000f }, + { nameof(steerMult), 200f }, + { nameof(steerKiAdjust), 20f }, + { nameof(steerDamping), 100f }, + { nameof(maxSpeed), 3000f }, + { nameof(takeOffSpeed), 2000f }, + { nameof(minSpeed), 2000f }, + { nameof(idleSpeed), 3000f }, + { nameof(maxAllowedGForce), 1000f }, + { nameof(maxAllowedAoA), 180f }, + }; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_StandbyMode"),//Standby Mode + UI_Toggle(enabledText = "#LOC_BDArmory_On", disabledText = "#LOC_BDArmory_Off")]//On--Off + public bool standbyMode = false; + + //manueuverability and g loading data + float maxDynPresGRecorded; + + float maxPosG; + float cosAoAAtMaxPosG; + + float maxNegG; + float cosAoAAtMaxNegG; + + float[] gLoadMovingAvgArray = new float[32]; + float[] cosAoAMovingAvgArray = new float[32]; + int movingAvgIndex; + + float gLoadMovingAvg; + float cosAoAMovingAvg; + + float gaoASlopePerDynPres; //used to limit control input at very high dynamic pressures to avoid structural failure + float gOffsetPerDynPres; + + float posPitchDynPresLimitIntegrator = 1; + float negPitchDynPresLimitIntegrator = -1; + + float lastCosAoA; + float lastPitchInput; + + //Controller Integral + float pitchIntegral; + float yawIntegral; + + //instantaneous turn radius and possible acceleration from lift + //properties can be used so that other AI modules can read this for future maneuverability comparisons between craft + float turnRadius; + + public float TurnRadius + { + get { return turnRadius; } + private set { turnRadius = value; } + } + + float maxLiftAcceleration; + + public float MaxLiftAcceleration + { + get { return maxLiftAcceleration; } + private set { maxLiftAcceleration = value; } + } + + float turningTimer; + float evasiveTimer; + Vector3 lastTargetPosition; + + LineRenderer lr; + Vector3 flyingToPosition; + Vector3 rollTarget; + Vector3 angVelRollTarget; + + //speed controller + bool useAB = true; + bool useBrakes = true; + bool regainEnergy = false; + + //collision detection + int collisionDetectionTicker; + float collisionDetectionTimer; + Vector3 collisionAvoidDirection; + + //wing command + bool useRollHint; + private Vector3d debugFollowPosition; + + double commandSpeed; + Vector3d commandHeading; + + float finalMaxSteer = 1; + + #region RMB info in editor + + // Yes + public override string GetInfo() + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Available settings:"); + sb.AppendLine($"- Default Alt. - altitude to fly at when cruising/idle"); + sb.AppendLine($"- Min Altitude - below this altitude AI will prioritize gaining altitude over combat"); + sb.AppendLine($"- Steer Factor - higher will make the AI apply more control input for the same desired rotation"); + sb.AppendLine($"- Steer Ki - higher will make the AI apply control trim faster"); + sb.AppendLine($"- Steer Limiter - limit AI from applying full control input"); + sb.AppendLine($"- Steer Damping - higher will make the AI apply more control input when it wants to stop rotation"); + sb.AppendLine($"- Max Speed - AI will not fly faster than this"); + sb.AppendLine($"- TakeOff Speed - speed at which to start pitching up when taking off"); + sb.AppendLine($"- MinCombat Speed - AI will prioritize regaining speed over combat below this"); + sb.AppendLine($"- Idle Speed - Cruising speed when not in combat"); + sb.AppendLine($"- Max G - AI will try not to perform maneuvers at higher G than this"); + sb.AppendLine($"- Max AoA - AI will try not to exceed this angle of attack"); + if (GameSettings.ADVANCED_TWEAKABLES) + { + sb.AppendLine($"- Orbit - Which direction to orbit when idling over a location"); + sb.AppendLine($"- Unclamp tuning - Increases variable limits, no direct effect on behaviour"); + } + sb.AppendLine($"- Standby Mode - AI will not take off until an enemy is detected"); + + return sb.ToString(); + } + + #endregion RMB info in editor + + protected override void Start() + { + base.Start(); + + if (HighLogic.LoadedSceneIsFlight) + { + maxAllowedCosAoA = (float)Math.Cos(maxAllowedAoA * Math.PI / 180.0); + lastAllowedAoA = maxAllowedAoA; + } + } + + public override void ActivatePilot() + { + base.ActivatePilot(); + + belowMinAltitude = vessel.LandedOrSplashed; + prevTargetDir = vesselTransform.up; + } + + void Update() + { + if (BDArmorySettings.DRAW_DEBUG_LINES && pilotEnabled) + { + if (lr) + { + lr.enabled = true; + lr.SetPosition(0, vessel.ReferenceTransform.position); + lr.SetPosition(1, flyingToPosition); + } + else + { + lr = gameObject.AddComponent(); + lr.positionCount = 2; + lr.startWidth = 0.5f; + lr.endWidth = 0.5f; + } + + minSpeed = Mathf.Clamp(minSpeed, 0, idleSpeed - 20); + minSpeed = Mathf.Clamp(minSpeed, 0, maxSpeed - 20); + } + else + { + if (lr) + { + lr.enabled = false; + } + } + + // switch up the alt values if up to eleven is toggled + if (UpToEleven != toEleven) + { + using (var s = altMaxValues.Keys.ToList().GetEnumerator()) + while (s.MoveNext()) + { + UI_FloatRange euic = (UI_FloatRange) + (HighLogic.LoadedSceneIsFlight ? Fields[s.Current].uiControlFlight : Fields[s.Current].uiControlEditor); + float tempValue = euic.maxValue; + euic.maxValue = altMaxValues[s.Current]; + altMaxValues[s.Current] = tempValue; + // change the value back to what it is now after fixed update, because changing the max value will clamp it down + // using reflection here, don't look at me like that, this does not run often + StartCoroutine(setVar(s.Current, (float)typeof(BDModulePilotAI).GetField(s.Current).GetValue(this))); + } + toEleven = UpToEleven; + } + } + + IEnumerator setVar(string name, float value) + { + yield return new WaitForFixedUpdate(); + typeof(BDModulePilotAI).GetField(name).SetValue(this, value); + } + + void FixedUpdate() + { + //floating origin and velocity offloading corrections + if (lastTargetPosition != null && (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero())) + { + lastTargetPosition -= FloatingOrigin.OffsetNonKrakensbane; + } + } + + protected override void AutoPilot(FlightCtrlState s) + { + finalMaxSteer = maxSteer; + + //default brakes off full throttle + //s.mainThrottle = 1; + + //vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, false); + AdjustThrottle(maxSpeed, true); + useAB = true; + useBrakes = true; + vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, true); + + steerMode = SteerModes.NormalFlight; + useVelRollTarget = false; + + if (vessel.LandedOrSplashed && standbyMode && weaponManager && (BDATargetManager.GetClosestTarget(this.weaponManager) == null || BDArmorySettings.PEACE_MODE)) //TheDog: replaced querying of targetdatabase with actual check if a target can be detected + { + //s.mainThrottle = 0; + //vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); + AdjustThrottle(0, true); + return; + } + + //upDirection = -FlightGlobals.getGeeForceAtPosition(transform.position).normalized; + upDirection = VectorUtils.GetUpDirection(vessel.transform.position); + + CalculateAccelerationAndTurningCircle(); + float minAltNeeded = MinAltitudeNeeded(); + debugString.Append($"minAltNeeded: {minAltNeeded}"); + debugString.Append(Environment.NewLine); + + if (MissileGuidance.GetRadarAltitude(vessel) < minAltNeeded) + { + belowMinAltitude = true; + } + + if (vessel.srfSpeed < minSpeed) + { + regainEnergy = true; + } + else if (!belowMinAltitude && vessel.srfSpeed > Mathf.Min(minSpeed + 20f, idleSpeed)) + { + regainEnergy = false; + } + + if (belowMinAltitude) + { + if (command != PilotCommands.Follow) + { + currentStatus = "Gain Alt."; + } + TakeOff(s); + turningTimer = 0; + } + else + { + if (FlyAvoidCollision(s)) + { + turningTimer = 0; + } + else if (command != PilotCommands.Free) + { + UpdateCommand(s); + } + else + { + UpdateAI(s); + } + } + UpdateGAndAoALimits(s); + AdjustPitchForGAndAoALimits(s); + } + + void UpdateAI(FlightCtrlState s) + { + currentStatus = "Free"; + + if (requestedExtend) + { + requestedExtend = false; + extending = true; + lastTargetPosition = requestedExtendTpos; + } + + if (evasiveTimer > 0 || (weaponManager && (weaponManager.missileIsIncoming || weaponManager.isChaffing || weaponManager.isFlaring || weaponManager.underFire))) + { + if (evasiveTimer < 1) + { + threatRelativePosition = vessel.Velocity().normalized + vesselTransform.right; + + if (weaponManager) + { + if (weaponManager.rwr?.rwrEnabled ?? false) //use rwr to check missile threat direction + { + Vector3 missileThreat = Vector3.zero; + bool missileThreatDetected = false; + float closestMissileThreat = float.MaxValue; + for (int i = 0; i < weaponManager.rwr.pingsData.Length; i++) + { + TargetSignatureData threat = weaponManager.rwr.pingsData[i]; + if (threat.exists && threat.signalStrength == 4) + { + missileThreatDetected = true; + float dist = (weaponManager.rwr.pingWorldPositions[i] - vesselTransform.position).sqrMagnitude; + if (dist < closestMissileThreat) + { + closestMissileThreat = dist; + missileThreat = weaponManager.rwr.pingWorldPositions[i]; + } + } + } + if (missileThreatDetected) + { + threatRelativePosition = missileThreat - vesselTransform.position; + } + } + + if (weaponManager.underFire) + { + threatRelativePosition = weaponManager.incomingThreatPosition - vesselTransform.position; + } + } + } + Evasive(s); + evasiveTimer += Time.fixedDeltaTime; + turningTimer = 0; + + if (evasiveTimer > 3) + { + evasiveTimer = 0; + collisionDetectionTicker = 21; //check for collision again after exiting evasion routine + } + } + else if (!extending && weaponManager && targetVessel != null && targetVessel.transform != null) + { + evasiveTimer = 0; + if (!targetVessel.LandedOrSplashed) + { + Vector3 targetVesselRelPos = targetVessel.vesselTransform.position - vesselTransform.position; + if (vessel.altitude < defaultAltitude && Vector3.Angle(targetVesselRelPos, -upDirection) < 35) + { + //dangerous if low altitude and target is far below you - don't dive into ground! + extending = true; + lastTargetPosition = targetVessel.vesselTransform.position; + } + + if (Vector3.Angle(targetVessel.vesselTransform.position - vesselTransform.position, vesselTransform.up) > 35) + { + turningTimer += Time.deltaTime; + } + else + { + turningTimer = 0; + } + + debugString.Append($"turningTimer: {turningTimer}"); + debugString.Append(Environment.NewLine); + + float targetForwardDot = Vector3.Dot(targetVesselRelPos.normalized, vesselTransform.up); + float targetVelFrac = (float)(targetVessel.srfSpeed / vessel.srfSpeed); //this is the ratio of the target vessel's velocity to this vessel's srfSpeed in the forward direction; this allows smart decisions about when to break off the attack + + if (targetVelFrac < 0.8f && targetForwardDot < 0.2f && targetVesselRelPos.magnitude < 400) + { + extending = true; + lastTargetPosition = targetVessel.vesselTransform.position - vessel.Velocity(); //we'll set our last target pos based on the enemy vessel and where we were 1 seconds ago + weaponManager.ForceScan(); + } + if (turningTimer > 15) + { + //extend if turning circles for too long + //extending = true; + RequestExtend(targetVessel.vesselTransform.position); + turningTimer = 0; + weaponManager.ForceScan(); + //lastTargetPosition = targetVessel.transform.position; + } + } + else //extend if too close for agm attack + { + float extendDistance = Mathf.Clamp(weaponManager.guardRange - 1800, 2500, 4000); + float srfDist = (GetSurfacePosition(targetVessel.transform.position) - GetSurfacePosition(vessel.transform.position)).sqrMagnitude; + + if (srfDist < extendDistance * extendDistance && Vector3.Angle(vesselTransform.up, targetVessel.transform.position - vessel.transform.position) > 45) + { + extending = true; + lastTargetPosition = targetVessel.transform.position; + weaponManager.ForceScan(); + } + } + + if (!extending) + { + currentStatus = "Engaging"; + debugString.Append($"Flying to target"); + debugString.Append(Environment.NewLine); + FlyToTargetVessel(s, targetVessel); + } + } + else + { + evasiveTimer = 0; + if (!extending) + { + currentStatus = "Orbiting"; + FlyOrbit(s, assignedPositionGeo, 2000, idleSpeed, ClockwiseOrbit); + } + } + + if (extending) + { + evasiveTimer = 0; + currentStatus = "Extending"; + debugString.Append($"Extending"); + debugString.Append(Environment.NewLine); + FlyExtend(s, lastTargetPosition); + } + } + + bool FlyAvoidCollision(FlightCtrlState s) + { + if (collisionDetectionTimer > 2) + { + collisionDetectionTimer = 0; + collisionDetectionTicker = 20; + } + if (collisionDetectionTimer > 0) + { + //fly avoid + currentStatus = "AvoidCollision"; + debugString.Append($"Avoiding Collision"); + debugString.Append(Environment.NewLine); + collisionDetectionTimer += Time.fixedDeltaTime; + + Vector3 target = vesselTransform.position + collisionAvoidDirection; + FlyToPosition(s, target); + return true; + } + else if (collisionDetectionTicker > 20) + { + collisionDetectionTicker = 0; + bool avoid = false; + Vector3 badDirection; + if (DetectCollision(flyingToPosition - vesselTransform.position, out badDirection)) + { + avoid = true; + } + else if (command != PilotCommands.Follow) //check collisions with other flying vessels + { + List.Enumerator vs = BDATargetManager.LoadedVessels.GetEnumerator(); + while (vs.MoveNext()) + { + if (vs.Current == null) continue; + if (vs.Current == vessel || vs.Current.Landed || + !(Vector3.Dot(vs.Current.transform.position - vesselTransform.position, + vesselTransform.up) > 0)) continue; + if (!PredictCollisionWithVessel(vs.Current, 2.5f, 0.5f, out badDirection)) continue; + // the 'isLeadingFormation' check was bad anyway, as releasing one member would unset it, while still having other followers, moving it here + if (vs.Current.FindPartModuleImplementing()?.commandLeader?.vessel == vessel) continue; + avoid = true; + break; + } + vs.Dispose(); + } + + if (!avoid) return false; + collisionDetectionTimer += Time.fixedDeltaTime; + Vector3 axis = -Vector3.Cross(vesselTransform.up, badDirection); + collisionAvoidDirection = Quaternion.AngleAxis(25, axis) * badDirection; //don't need to change the angle that much to avoid, and it should prevent stupid suicidal manuevers as well + + FlyAvoidCollision(s); + return true; + } + else + { + collisionDetectionTicker++; + } + + return false; + } + + bool PredictCollisionWithVessel(Vessel v, float maxTime, float interval, out Vector3 badDirection) + { + if (vessel == null || v == null || v == weaponManager?.incomingMissileVessel + || v.rootPart.FindModuleImplementing() != null) //evasive will handle avoiding missiles + { + badDirection = Vector3.zero; + return false; + } + + float time = Mathf.Min(0.5f, maxTime); + while (time < maxTime) + { + Vector3 tPos = AIUtils.PredictPosition(v, time); + Vector3 myPos = AIUtils.PredictPosition(vessel, time); + if (Vector3.SqrMagnitude(tPos - myPos) < 900f) + { + badDirection = tPos - vesselTransform.position; + return true; + } + + time = Mathf.MoveTowards(time, maxTime, interval); + } + + badDirection = Vector3.zero; + return false; + } + + void FlyToTargetVessel(FlightCtrlState s, Vessel v) + { + Vector3 target = v.CoM; + MissileBase missile = null; + Vector3 vectorToTarget = v.transform.position - vesselTransform.position; + float distanceToTarget = vectorToTarget.magnitude; + float planarDistanceToTarget = Vector3.ProjectOnPlane(vectorToTarget, upDirection).magnitude; + float angleToTarget = Vector3.Angle(target - vesselTransform.position, vesselTransform.up); + if (weaponManager) + { + missile = weaponManager.CurrentMissile; + if (missile != null) + { + if (missile.GetWeaponClass() == WeaponClasses.Missile) + { + if (distanceToTarget > 5500f) + { + finalMaxSteer = GetSteerLimiterForSpeedAndPower(); + } + + if (missile.TargetingMode == MissileBase.TargetingModes.Heat && !weaponManager.heatTarget.exists) + { + debugString.Append($"Attempting heat lock"); + debugString.Append(Environment.NewLine); + target += v.srf_velocity.normalized * 10; + } + else + { + target = MissileGuidance.GetAirToAirFireSolution(missile, v); + } + + if (angleToTarget < 20f) + { + steerMode = SteerModes.Aiming; + } + } + else //bombing + { + if (distanceToTarget > 4500f) + { + finalMaxSteer = GetSteerLimiterForSpeedAndPower(); + } + + if (angleToTarget < 45f) + { + target = target + (Mathf.Max(defaultAltitude - 500f, minAltitude) * upDirection); + Vector3 tDir = (target - vesselTransform.position).normalized; + tDir = (1000 * tDir) - (vessel.Velocity().normalized * 600); + target = vesselTransform.position + tDir; + } + else + { + target = target + (Mathf.Max(defaultAltitude - 500f, minAltitude) * upDirection); + } + } + } + else if (weaponManager.currentGun) + { + ModuleWeapon weapon = weaponManager.currentGun; + if (weapon != null) + { + Vector3 leadOffset = weapon.GetLeadOffset(); + + float targetAngVel = Vector3.Angle(v.transform.position - vessel.transform.position, v.transform.position + (vessel.Velocity()) - vessel.transform.position); + debugString.Append($"targetAngVel: {targetAngVel}"); + debugString.Append(Environment.NewLine); + float magnifier = Mathf.Clamp(targetAngVel, 1f, 2f); + magnifier += ((magnifier - 1f) * Mathf.Sin(Time.time * 0.75f)); + target -= magnifier * leadOffset; + + angleToTarget = Vector3.Angle(vesselTransform.up, target - vesselTransform.position); + if (distanceToTarget < weaponManager.gunRange && angleToTarget < 20) + { + steerMode = SteerModes.Aiming; //steer to aim + } + else + { + if (distanceToTarget > 3500f || vessel.srfSpeed < takeOffSpeed) + { + finalMaxSteer = GetSteerLimiterForSpeedAndPower(); + } + else + { + //figuring how much to lead the target's movement to get there after its movement assuming we can manage a constant speed turn + //this only runs if we're not aiming and not that far from the target + float curVesselMaxAccel = Math.Min(maxDynPresGRecorded * (float)vessel.dynamicPressurekPa, maxAllowedGForce * 9.81f); + if (curVesselMaxAccel > 0) + { + float timeToTurn = (float)vessel.srfSpeed * angleToTarget * Mathf.Deg2Rad / curVesselMaxAccel; + target += v.Velocity() * timeToTurn; + //target += 0.5f * v.acceleration * timeToTurn * timeToTurn; + } + } + } + + if (v.LandedOrSplashed) + { + if (distanceToTarget > defaultAltitude * 2.2f) + { + target = FlightPosition(target, defaultAltitude); + } + else + { + steerMode = SteerModes.Aiming; + } + } + else if (distanceToTarget > weaponManager.gunRange * 1.5f || Vector3.Dot(target - vesselTransform.position, vesselTransform.up) < 0) + { + target = v.CoM; + } + } + } + else if (planarDistanceToTarget > weaponManager.gunRange * 1.25f && (vessel.altitude < targetVessel.altitude || MissileGuidance.GetRadarAltitude(vessel) < defaultAltitude)) //climb to target vessel's altitude if lower and still too far for guns + { + finalMaxSteer = GetSteerLimiterForSpeedAndPower(); + target = vesselTransform.position + GetLimitedClimbDirectionForSpeed(vectorToTarget); + } + else + { + finalMaxSteer = GetSteerLimiterForSpeedAndPower(); + } + } + + float targetDot = Vector3.Dot(vesselTransform.up, v.transform.position - vessel.transform.position); + + //manage speed when close to enemy + float finalMaxSpeed = maxSpeed; + if (targetDot > 0) + { + finalMaxSpeed = Mathf.Max((distanceToTarget - 100) / 8, 0) + (float)v.srfSpeed; + finalMaxSpeed = Mathf.Max(finalMaxSpeed, minSpeed + 25f); + } + AdjustThrottle(finalMaxSpeed, true); + + if ((targetDot < 0 && vessel.srfSpeed > finalMaxSpeed) + && distanceToTarget < 300 && vessel.srfSpeed < v.srfSpeed * 1.25f && Vector3.Dot(vessel.Velocity(), v.Velocity()) > 0) //distance is less than 800m + { + debugString.Append($"Enemy on tail. Braking!"); + debugString.Append(Environment.NewLine); + AdjustThrottle(minSpeed, true); + } + if (missile != null + && targetDot > 0 + && distanceToTarget < MissileLaunchParams.GetDynamicLaunchParams(missile, v.Velocity(), v.transform.position).minLaunchRange + && vessel.srfSpeed > idleSpeed) + { + //extending = true; + //lastTargetPosition = v.transform.position; + RequestExtend(lastTargetPosition); + } + + if (regainEnergy && angleToTarget > 30f) + { + RegainEnergy(s, target - vesselTransform.position); + return; + } + else + { + useVelRollTarget = true; + FlyToPosition(s, target); + return; + } + } + + void RegainEnergy(FlightCtrlState s, Vector3 direction) + { + debugString.Append($"Regaining energy"); + debugString.Append(Environment.NewLine); + + steerMode = SteerModes.Aiming; + Vector3 planarDirection = Vector3.ProjectOnPlane(direction, upDirection); + float angle = (Mathf.Clamp(MissileGuidance.GetRadarAltitude(vessel) - minAltitude, 0, 1500) / 1500) * 90; + angle = Mathf.Clamp(angle, 0, 55) * Mathf.Deg2Rad; + + Vector3 targetDirection = Vector3.RotateTowards(planarDirection, -upDirection, angle, 0); + targetDirection = Vector3.RotateTowards(vessel.Velocity(), targetDirection, 15f * Mathf.Deg2Rad, 0).normalized; + + AdjustThrottle(maxSpeed, false); + FlyToPosition(s, vesselTransform.position + (targetDirection * 100)); + } + + float GetSteerLimiterForSpeedAndPower() + { + float possibleAccel = speedController.GetPossibleAccel(); + float speed = (float)vessel.srfSpeed; + + debugString.Append($"possibleAccel: {possibleAccel}"); + debugString.Append(Environment.NewLine); + + float limiter = ((speed - 50) / 330f) + possibleAccel / 15f; + debugString.Append($"unclamped limiter: { limiter}"); + debugString.Append(Environment.NewLine); + + return Mathf.Clamp01(limiter); + } + + Vector3 prevTargetDir; + Vector3 debugPos; + bool useVelRollTarget; + + void FlyToPosition(FlightCtrlState s, Vector3 targetPosition) + { + if (!belowMinAltitude) + { + if (weaponManager && Time.time - weaponManager.timeBombReleased < 1.5f) + { + targetPosition = vessel.transform.position + vessel.Velocity(); + } + + targetPosition = FlightPosition(targetPosition, minAltitude); + targetPosition = vesselTransform.position + ((targetPosition - vesselTransform.position).normalized * 100); + } + + Vector3d srfVel = vessel.Velocity(); + if (srfVel != Vector3d.zero) + { + velocityTransform.rotation = Quaternion.LookRotation(srfVel, -vesselTransform.forward); + } + velocityTransform.rotation = Quaternion.AngleAxis(90, velocityTransform.right) * velocityTransform.rotation; + + //ang vel + Vector3 localAngVel = vessel.angularVelocity; + //test + Vector3 currTargetDir = (targetPosition - vesselTransform.position).normalized; + if (steerMode == SteerModes.NormalFlight) + { + float gRotVel = ((10f * maxAllowedGForce) / ((float)vessel.srfSpeed)); + //currTargetDir = Vector3.RotateTowards(prevTargetDir, currTargetDir, gRotVel*Mathf.Deg2Rad, 0); + } + Vector3 targetAngVel = Vector3.Cross(prevTargetDir, currTargetDir) / Time.fixedDeltaTime; + Vector3 localTargetAngVel = vesselTransform.InverseTransformVector(targetAngVel); + prevTargetDir = currTargetDir; + targetPosition = vessel.transform.position + (currTargetDir * 100); + + flyingToPosition = targetPosition; + + //test poststall + float AoA = Vector3.Angle(vessel.ReferenceTransform.up, vessel.Velocity()); + if (AoA > 30f) + { + steerMode = SteerModes.Aiming; + } + + //slow down for tighter turns + float velAngleToTarget = Vector3.Angle(targetPosition - vesselTransform.position, vessel.Velocity()); + float normVelAngleToTarget = Mathf.Clamp(velAngleToTarget, 0, 90) / 90; + float speedReductionFactor = 1.25f; + float finalSpeed = Mathf.Min(speedController.targetSpeed, Mathf.Clamp(maxSpeed - (speedReductionFactor * normVelAngleToTarget), idleSpeed, maxSpeed)); + debugString.Append($"Final Target Speed: {finalSpeed}"); + debugString.Append(Environment.NewLine); + AdjustThrottle(finalSpeed, useBrakes, useAB); + + if (steerMode == SteerModes.Aiming) + { + localAngVel -= localTargetAngVel; + } + + Vector3 targetDirection; + Vector3 targetDirectionYaw; + float yawError; + float pitchError; + //float postYawFactor; + //float postPitchFactor; + if (steerMode == SteerModes.NormalFlight) + { + targetDirection = velocityTransform.InverseTransformDirection(targetPosition - velocityTransform.position).normalized; + targetDirection = Vector3.RotateTowards(Vector3.up, targetDirection, 45 * Mathf.Deg2Rad, 0); + + targetDirectionYaw = vesselTransform.InverseTransformDirection(vessel.Velocity()).normalized; + targetDirectionYaw = Vector3.RotateTowards(Vector3.up, targetDirectionYaw, 45 * Mathf.Deg2Rad, 0); + } + else//(steerMode == SteerModes.Aiming) + { + targetDirection = vesselTransform.InverseTransformDirection(targetPosition - vesselTransform.position).normalized; + targetDirection = Vector3.RotateTowards(Vector3.up, targetDirection, 25 * Mathf.Deg2Rad, 0); + targetDirectionYaw = targetDirection; + } + debugPos = vessel.transform.position + (targetPosition - vesselTransform.position) * 5000; + + pitchError = VectorUtils.SignedAngle(Vector3.up, Vector3.ProjectOnPlane(targetDirection, Vector3.right), Vector3.back); + yawError = VectorUtils.SignedAngle(Vector3.up, Vector3.ProjectOnPlane(targetDirectionYaw, Vector3.forward), Vector3.right); + + //test + debugString.Append($"finalMaxSteer: {finalMaxSteer}"); + debugString.Append(Environment.NewLine); + + //roll + Vector3 currentRoll = -vesselTransform.forward; + float rollUp = (steerMode == SteerModes.Aiming ? 5f : 10f); + if (steerMode == SteerModes.NormalFlight) + { + rollUp += (1 - finalMaxSteer) * 10f; + } + rollTarget = (targetPosition + (rollUp * upDirection)) - vesselTransform.position; + + //test + if (steerMode == SteerModes.Aiming && !belowMinAltitude) + { + angVelRollTarget = -140 * vesselTransform.TransformVector(Quaternion.AngleAxis(90f, Vector3.up) * localTargetAngVel); + rollTarget += angVelRollTarget; + } + + if (command == PilotCommands.Follow && useRollHint) + { + rollTarget = -commandLeader.vessel.ReferenceTransform.forward; + } + + // + if (belowMinAltitude) + { + rollTarget = vessel.upAxis * 100; + } + if (useVelRollTarget && !belowMinAltitude) + { + rollTarget = Vector3.ProjectOnPlane(rollTarget, vessel.Velocity()); + currentRoll = Vector3.ProjectOnPlane(currentRoll, vessel.Velocity()); + } + else + { + rollTarget = Vector3.ProjectOnPlane(rollTarget, vesselTransform.up); + } + + //v/q + float dynamicAdjustment = Mathf.Clamp(16 * (float)(vessel.srfSpeed / vessel.dynamicPressurekPa), 0, 1.2f); + + float rollError = Misc.Misc.SignedAngle(currentRoll, rollTarget, vesselTransform.right); + float steerRoll = (steerMult * 0.0015f * rollError); + float rollDamping = (.10f * steerDamping * -localAngVel.y); + steerRoll -= rollDamping; + steerRoll *= dynamicAdjustment; + + if (steerMode == SteerModes.NormalFlight) + { + //premature dive fix + pitchError = pitchError * Mathf.Clamp01((21 - Mathf.Exp(Mathf.Abs(rollError) / 30)) / 20); + } + + float steerPitch = (0.015f * steerMult * pitchError) - (steerDamping * -localAngVel.x * (1 + steerKiAdjust)); + float steerYaw = (0.005f * steerMult * yawError) - (steerDamping * 0.2f * -localAngVel.z * (1 + steerKiAdjust)); + + pitchIntegral += pitchError; + yawIntegral += yawError; + + steerPitch *= dynamicAdjustment; + steerYaw *= dynamicAdjustment; + + float pitchKi = 0.1f * (steerKiAdjust / 5); //This is what should be allowed to be tweaked by the player, just like the steerMult, it is very low right now + pitchIntegral = Mathf.Clamp(pitchIntegral, -0.2f / (pitchKi * dynamicAdjustment), 0.2f / (pitchKi * dynamicAdjustment)); //0.2f is the limit of the integral variable, making it bigger increases overshoot + steerPitch += pitchIntegral * pitchKi * dynamicAdjustment; //Adds the integral component to the mix + + float yawKi = 0.1f * (steerKiAdjust / 15); + yawIntegral = Mathf.Clamp(yawIntegral, -0.2f / (yawKi * dynamicAdjustment), 0.2f / (yawKi * dynamicAdjustment)); + steerYaw += yawIntegral * yawKi * dynamicAdjustment; + + float roll = Mathf.Clamp(steerRoll, -maxSteer, maxSteer); + s.roll = roll; + s.yaw = Mathf.Clamp(steerYaw, -finalMaxSteer, finalMaxSteer); + s.pitch = Mathf.Clamp(steerPitch, Mathf.Min(-finalMaxSteer, -0.2f), finalMaxSteer); + } + + void FlyExtend(FlightCtrlState s, Vector3 tPosition) + { + if (weaponManager) + { + if (weaponManager.TargetOverride) + { + extending = false; + } + + float extendDistance = Mathf.Clamp(weaponManager.guardRange - 1800, 2500, 4000); + + if (weaponManager.CurrentMissile && weaponManager.CurrentMissile.GetWeaponClass() == WeaponClasses.Bomb) + { + extendDistance = 4500; + } + + if (targetVessel != null && !targetVessel.LandedOrSplashed) //this is just asking for trouble at 800m + { + extendDistance = 1600; + } + + Vector3 srfVector = Vector3.ProjectOnPlane(vessel.transform.position - tPosition, upDirection); + float srfDist = srfVector.magnitude; + if (srfDist < extendDistance) + { + Vector3 targetDirection = srfVector.normalized * extendDistance; + Vector3 target = vessel.transform.position + targetDirection; + target = GetTerrainSurfacePosition(target) + (vessel.upAxis * Mathf.Min(defaultAltitude, MissileGuidance.GetRaycastRadarAltitude(vesselTransform.position))); + target = FlightPosition(target, defaultAltitude); + if (regainEnergy) + { + RegainEnergy(s, target - vesselTransform.position); + return; + } + else + { + FlyToPosition(s, target); + } + } + else + { + extending = false; + } + } + else + { + extending = false; + } + } + + void FlyOrbit(FlightCtrlState s, Vector3d centerGPS, float radius, float speed, bool clockwise) + { + if (regainEnergy) + { + RegainEnergy(s, vessel.Velocity()); + return; + } + + finalMaxSteer = GetSteerLimiterForSpeedAndPower(); + + debugString.Append($"Flying orbit"); + debugString.Append(Environment.NewLine); + Vector3 flightCenter = GetTerrainSurfacePosition(VectorUtils.GetWorldSurfacePostion(centerGPS, vessel.mainBody)) + (defaultAltitude * upDirection); + + Vector3 myVectorFromCenter = Vector3.ProjectOnPlane(vessel.transform.position - flightCenter, upDirection); + Vector3 myVectorOnOrbit = myVectorFromCenter.normalized * radius; + + Vector3 targetVectorFromCenter = Quaternion.AngleAxis(clockwise ? 15f : -15f, upDirection) * myVectorOnOrbit; + + Vector3 verticalVelVector = Vector3.Project(vessel.Velocity(), upDirection); //for vv damping + + Vector3 targetPosition = flightCenter + targetVectorFromCenter - (verticalVelVector * 0.25f); + + Vector3 vectorToTarget = targetPosition - vesselTransform.position; + //Vector3 planarVel = Vector3.ProjectOnPlane(vessel.Velocity(), upDirection); + //vectorToTarget = Vector3.RotateTowards(planarVel, vectorToTarget, 25f * Mathf.Deg2Rad, 0); + vectorToTarget = GetLimitedClimbDirectionForSpeed(vectorToTarget); + targetPosition = vesselTransform.position + vectorToTarget; + + if (command != PilotCommands.Free && (vessel.transform.position - flightCenter).sqrMagnitude < radius * radius * 1.5f) + { + Debug.Log("[BDArmory]: AI Pilot reached command destination."); + command = PilotCommands.Free; + } + + useVelRollTarget = true; + + AdjustThrottle(speed, false); + FlyToPosition(s, targetPosition); + } + + //sends target speed to speedController + void AdjustThrottle(float targetSpeed, bool useBrakes, bool allowAfterburner = true) + { + speedController.targetSpeed = targetSpeed; + speedController.useBrakes = useBrakes; + speedController.allowAfterburner = allowAfterburner; + } + + Vector3 threatRelativePosition; + + void Evasive(FlightCtrlState s) + { + if (s == null) return; + if (vessel == null) return; + if (weaponManager == null) return; + + currentStatus = "Evading"; + debugString.Append($"Evasive"); + debugString.Append(Environment.NewLine); + debugString.Append($"Threat Distance: {weaponManager.incomingMissileDistance}"); + debugString.Append(Environment.NewLine); + + collisionDetectionTicker += 2; + + if (weaponManager) + { + if (weaponManager.isFlaring) + { + useAB = vessel.srfSpeed < minSpeed; + useBrakes = false; + float targetSpeed = minSpeed; + if (weaponManager.isChaffing) + { + targetSpeed = maxSpeed; + } + AdjustThrottle(targetSpeed, false, useAB); + } + + if ((weaponManager.isChaffing || weaponManager.isFlaring) && (weaponManager.incomingMissileDistance > 2000)) + { + debugString.Append($"Breaking from missile threat!"); + debugString.Append(Environment.NewLine); + + Vector3 axis = -Vector3.Cross(vesselTransform.up, threatRelativePosition); + Vector3 breakDirection = Quaternion.AngleAxis(90, axis) * threatRelativePosition; + //Vector3 breakTarget = vesselTransform.position + breakDirection; + RegainEnergy(s, breakDirection); + return; + } + else if (weaponManager.underFire) + { + debugString.Append($"Dodging gunfire"); + float threatDirectionFactor = Vector3.Dot(vesselTransform.up, threatRelativePosition.normalized); + //Vector3 axis = -Vector3.Cross(vesselTransform.up, threatRelativePosition); + + Vector3 breakTarget = threatRelativePosition * 2f; //for the most part, we want to turn _towards_ the threat in order to increase the rel ang vel and get under its guns + + if (threatDirectionFactor > 0.9f) //within 28 degrees in front + { + breakTarget += Vector3.Cross(threatRelativePosition.normalized, Mathf.Sign(Mathf.Sin((float)vessel.missionTime / 2)) * vessel.upAxis); + debugString.Append($" from directly ahead!"); + } + else if (threatDirectionFactor < -0.9) //within ~28 degrees behind + { + float threatDistance = threatRelativePosition.magnitude; + if (threatDistance > 400) + { + breakTarget = vesselTransform.position + vesselTransform.up * 1500 - 500 * vessel.upAxis; + breakTarget += Mathf.Sin((float)vessel.missionTime / 2) * vesselTransform.right * 1000 - Mathf.Cos((float)vessel.missionTime / 2) * vesselTransform.forward * 1000; + if (threatDistance > 800) + debugString.Append($" from behind afar; engaging barrel roll"); + else + { + debugString.Append($" from behind moderate distance; engaging aggressvie barrel roll and braking"); + steerMode = SteerModes.Aiming; + AdjustThrottle(minSpeed, true, false); + } + } + else + { + breakTarget = threatRelativePosition; + if (evasiveTimer < 1.5f) + breakTarget += Mathf.Sin((float)vessel.missionTime * 2) * vesselTransform.right * 500; + else + breakTarget += -Math.Sign(Mathf.Sin((float)vessel.missionTime * 2)) * vesselTransform.right * 150; + + debugString.Append($" from directly behind and close; breaking hard"); + steerMode = SteerModes.Aiming; + } + } + else + { + float threatDistance = threatRelativePosition.magnitude; + if (threatDistance < 400) + { + breakTarget += Mathf.Sin((float)vessel.missionTime * 2) * vesselTransform.right * 100; + + steerMode = SteerModes.Aiming; + } + else + { + breakTarget = vesselTransform.position + vesselTransform.up * 1500; + breakTarget += Mathf.Sin((float)vessel.missionTime / 2) * vesselTransform.right * 1000 - Mathf.Cos((float)vessel.missionTime / 2) * vesselTransform.forward * 1000; + debugString.Append($" from far side; engaging barrel roll"); + } + } + + float threatAltitudeDiff = Vector3.Dot(threatRelativePosition, vessel.upAxis); + if (threatAltitudeDiff > 500) + breakTarget += threatAltitudeDiff * vessel.upAxis; //if it's trying to spike us from below, don't go crazy trying to dive below it + else + breakTarget += -150 * vessel.upAxis; //dive a bit to escape + + FlyToPosition(s, breakTarget); + return; + } + else if (weaponManager.incomingMissileVessel) + { + float mSqrDist = Vector3.SqrMagnitude(weaponManager.incomingMissileVessel.transform.position - vesselTransform.position); + if (mSqrDist < 810000) //900m + { + debugString.Append($"Missile about to impact! pull away!"); + debugString.Append(Environment.NewLine); + + AdjustThrottle(maxSpeed, false, false); + Vector3 cross = Vector3.Cross(weaponManager.incomingMissileVessel.transform.position - vesselTransform.position, vessel.Velocity()).normalized; + if (Vector3.Dot(cross, -vesselTransform.forward) < 0) + { + cross = -cross; + } + FlyToPosition(s, vesselTransform.position + (50 * vessel.Velocity() / vessel.srfSpeed) + (100 * cross)); + return; + } + } + } + + Vector3 target = (vessel.srfSpeed < 200) ? FlightPosition(vessel.transform.position, minAltitude) : vesselTransform.position; + float angleOff = Mathf.Sin(Time.time * 0.75f) * 180; + angleOff = Mathf.Clamp(angleOff, -45, 45); + target += + (Quaternion.AngleAxis(angleOff, upDirection) * Vector3.ProjectOnPlane(vesselTransform.up * 500, upDirection)); + //+ (Mathf.Sin (Time.time/3) * upDirection * minAltitude/3); + + FlyToPosition(s, target); + } + + void TakeOff(FlightCtrlState s) + { + debugString.Append($"Taking off/Gaining altitude"); + debugString.Append(Environment.NewLine); + + if (vessel.LandedOrSplashed && vessel.srfSpeed < takeOffSpeed) + { + assignedPositionWorld = vessel.transform.position; + return; + } + + steerMode = SteerModes.Aiming; + + float radarAlt = MissileGuidance.GetRadarAltitude(vessel); + + Vector3 forwardPoint = vessel.transform.position + Vector3.ProjectOnPlane((vessel.horizontalSrfSpeed < 10 ? vesselTransform.up : (Vector3)vessel.srf_vel_direction) * 100, upDirection); + float terrainDiff = MissileGuidance.GetRaycastRadarAltitude(forwardPoint) - radarAlt; + terrainDiff = Mathf.Max(terrainDiff, 0); + + float rise = Mathf.Clamp((float)vessel.srfSpeed * 0.215f, 5, 100); + + if (radarAlt > 70) + { + vessel.ActionGroups.SetGroup(KSPActionGroup.Gear, false); + } + else + { + vessel.ActionGroups.SetGroup(KSPActionGroup.Gear, true); + } + + FlyToPosition(s, forwardPoint + (upDirection * (rise + terrainDiff))); + + if (radarAlt > minAltitude) + { + belowMinAltitude = false; + } + } + + Vector3 GetLimitedClimbDirectionForSpeed(Vector3 direction) + { + if (Vector3.Dot(direction, upDirection) < 0) + { + debugString.Append($"climb limit angle: unlimited"); + debugString.Append(Environment.NewLine); + return direction; //only use this if climbing + } + + Vector3 planarDirection = Vector3.ProjectOnPlane(direction, upDirection).normalized * 100; + + float angle = Mathf.Clamp((float)vessel.srfSpeed * 0.13f, 5, 90); + + debugString.Append($"climb limit angle: {angle}"); + debugString.Append(Environment.NewLine); + return Vector3.RotateTowards(planarDirection, direction, angle * Mathf.Deg2Rad, 0); + } + + void UpdateGAndAoALimits(FlightCtrlState s) + { + if (vessel.dynamicPressurekPa <= 0 || vessel.srfSpeed < takeOffSpeed || belowMinAltitude && -Vector3.Dot(vessel.ReferenceTransform.forward, vessel.upAxis) < 0.8f) + { + return; + } + + if (lastAllowedAoA != maxAllowedAoA) + { + lastAllowedAoA = maxAllowedAoA; + maxAllowedCosAoA = (float)Math.Cos(lastAllowedAoA * Math.PI / 180.0); + } + float pitchG = -Vector3.Dot(vessel.acceleration, vessel.ReferenceTransform.forward); //should provide g force in vessel up / down direction, assuming a standard plane + float pitchGPerDynPres = pitchG / (float)vessel.dynamicPressurekPa; + + float curCosAoA = Vector3.Dot(vessel.Velocity().normalized, vessel.ReferenceTransform.forward); + + //adjust moving averages + //adjust gLoad average + gLoadMovingAvg *= 32f; + gLoadMovingAvg -= gLoadMovingAvgArray[movingAvgIndex]; + gLoadMovingAvgArray[movingAvgIndex] = pitchGPerDynPres; + gLoadMovingAvg += pitchGPerDynPres; + gLoadMovingAvg /= 32f; + + //adjusting cosAoAAvg + cosAoAMovingAvg *= 32f; + cosAoAMovingAvg -= cosAoAMovingAvgArray[movingAvgIndex]; + cosAoAMovingAvgArray[movingAvgIndex] = curCosAoA; + cosAoAMovingAvg += curCosAoA; + cosAoAMovingAvg /= 32f; + + ++movingAvgIndex; + if (movingAvgIndex == gLoadMovingAvgArray.Length) + movingAvgIndex = 0; + + if (gLoadMovingAvg < maxNegG || Math.Abs(cosAoAMovingAvg - cosAoAAtMaxNegG) < 0.005f) + { + maxNegG = gLoadMovingAvg; + cosAoAAtMaxNegG = cosAoAMovingAvg; + } + if (gLoadMovingAvg > maxPosG || Math.Abs(cosAoAMovingAvg - cosAoAAtMaxPosG) < 0.005f) + { + maxPosG = gLoadMovingAvg; + cosAoAAtMaxPosG = cosAoAMovingAvg; + } + + if (cosAoAAtMaxNegG >= cosAoAAtMaxPosG) + { + cosAoAAtMaxNegG = cosAoAAtMaxPosG = maxNegG = maxPosG = 0; + gOffsetPerDynPres = gaoASlopePerDynPres = 0; + return; + } + + if (maxPosG > maxDynPresGRecorded) + maxDynPresGRecorded = maxPosG; + + float aoADiff = cosAoAAtMaxPosG - cosAoAAtMaxNegG; + + //if (Math.Abs(pitchControlDiff) < 0.005f) + // return; //if the pitch control values are too similar, don't bother to avoid numerical errors + + gaoASlopePerDynPres = (maxPosG - maxNegG) / aoADiff; + gOffsetPerDynPres = maxPosG - gaoASlopePerDynPres * cosAoAAtMaxPosG; //g force offset + } + + void AdjustPitchForGAndAoALimits(FlightCtrlState s) + { + float minCosAoA, maxCosAoA; + //debugString += "\nMax Pos G: " + maxPosG + " @ " + cosAoAAtMaxPosG; + //debugString += "\nMax Neg G: " + maxNegG + " @ " + cosAoAAtMaxNegG; + + if (vessel.LandedOrSplashed || vessel.srfSpeed < Math.Min(minSpeed, takeOffSpeed)) //if we're going too slow, don't use this + { + float speed = Math.Max(takeOffSpeed, minSpeed); + negPitchDynPresLimitIntegrator = -1f * 0.001f * 0.5f * 1.225f * speed * speed; + posPitchDynPresLimitIntegrator = 1f * 0.001f * 0.5f * 1.225f * speed * speed; + return; + } + + float invVesselDynPreskPa = 1f / (float)vessel.dynamicPressurekPa; + + maxCosAoA = maxAllowedGForce * 9.81f * invVesselDynPreskPa; + minCosAoA = -maxCosAoA; + + maxCosAoA -= gOffsetPerDynPres; + minCosAoA -= gOffsetPerDynPres; + + maxCosAoA /= gaoASlopePerDynPres; + minCosAoA /= gaoASlopePerDynPres; + + if (maxCosAoA > maxAllowedCosAoA) + maxCosAoA = maxAllowedCosAoA; + + if (minCosAoA < -maxAllowedCosAoA) + minCosAoA = -maxAllowedCosAoA; + + float curCosAoA = Vector3.Dot(vessel.Velocity() / vessel.srfSpeed, vessel.ReferenceTransform.forward); + + float centerCosAoA = (minCosAoA + maxCosAoA) * 0.5f; + float curCosAoACentered = curCosAoA - centerCosAoA; + float cosAoADiff = 0.5f * Math.Abs(maxCosAoA - minCosAoA); + float curCosAoANorm = curCosAoACentered / cosAoADiff; //scaled so that from centerAoA to maxAoA is 1 + + float negPitchScalar, posPitchScalar; + negPitchScalar = negPitchDynPresLimitIntegrator * invVesselDynPreskPa - lastPitchInput; + posPitchScalar = lastPitchInput - posPitchDynPresLimitIntegrator * invVesselDynPreskPa; + + //update pitch control limits as needed + float negPitchDynPresLimit, posPitchDynPresLimit; + negPitchDynPresLimit = posPitchDynPresLimit = 0; + if (curCosAoANorm < -0.15f)// || Math.Abs(negPitchScalar) < 0.01f) + { + float cosAoAOffset = curCosAoANorm + 1; //set max neg aoa to be 0 + float aoALimScalar = Math.Abs(curCosAoANorm); + aoALimScalar *= aoALimScalar; + aoALimScalar *= aoALimScalar; + aoALimScalar *= aoALimScalar; + if (aoALimScalar > 1) + aoALimScalar = 1; + + float pitchInputScalar = negPitchScalar; + pitchInputScalar = 1 - Mathf.Clamp01(Math.Abs(pitchInputScalar)); + pitchInputScalar *= pitchInputScalar; + pitchInputScalar *= pitchInputScalar; + pitchInputScalar *= pitchInputScalar; + if (pitchInputScalar < 0) + pitchInputScalar = 0; + + float deltaCosAoANorm = curCosAoA - lastCosAoA; + deltaCosAoANorm /= cosAoADiff; + + debugString.Append($"Updating Neg Gs"); + debugString.Append(Environment.NewLine); + negPitchDynPresLimitIntegrator -= 0.01f * Mathf.Clamp01(aoALimScalar + pitchInputScalar) * cosAoAOffset * (float)vessel.dynamicPressurekPa; + negPitchDynPresLimitIntegrator -= 0.005f * deltaCosAoANorm * (float)vessel.dynamicPressurekPa; + if (cosAoAOffset < 0) + negPitchDynPresLimit = -0.3f * cosAoAOffset; + } + if (curCosAoANorm > 0.15f)// || Math.Abs(posPitchScalar) < 0.01f) + { + float cosAoAOffset = curCosAoANorm - 1; //set max pos aoa to be 0 + float aoALimScalar = Math.Abs(curCosAoANorm); + aoALimScalar *= aoALimScalar; + aoALimScalar *= aoALimScalar; + aoALimScalar *= aoALimScalar; + if (aoALimScalar > 1) + aoALimScalar = 1; + + float pitchInputScalar = posPitchScalar; + pitchInputScalar = 1 - Mathf.Clamp01(Math.Abs(pitchInputScalar)); + pitchInputScalar *= pitchInputScalar; + pitchInputScalar *= pitchInputScalar; + pitchInputScalar *= pitchInputScalar; + if (pitchInputScalar < 0) + pitchInputScalar = 0; + + float deltaCosAoANorm = curCosAoA - lastCosAoA; + deltaCosAoANorm /= cosAoADiff; + + debugString.Append($"Updating Pos Gs"); + debugString.Append(Environment.NewLine); + posPitchDynPresLimitIntegrator -= 0.01f * Mathf.Clamp01(aoALimScalar + pitchInputScalar) * cosAoAOffset * (float)vessel.dynamicPressurekPa; + posPitchDynPresLimitIntegrator -= 0.005f * deltaCosAoANorm * (float)vessel.dynamicPressurekPa; + if (cosAoAOffset > 0) + posPitchDynPresLimit = -0.3f * cosAoAOffset; + } + + float currentG = -Vector3.Dot(vessel.acceleration, vessel.ReferenceTransform.forward); + float negLim, posLim; + negLim = negPitchDynPresLimitIntegrator * invVesselDynPreskPa + negPitchDynPresLimit; + if (negLim > s.pitch) + { + if (currentG > -(maxAllowedGForce * 0.97f * 9.81f)) + { + negPitchDynPresLimitIntegrator -= (float)(0.15 * vessel.dynamicPressurekPa); //jsut an override in case things break + + maxNegG = currentG * invVesselDynPreskPa; + cosAoAAtMaxNegG = curCosAoA; + + negPitchDynPresLimit = 0; + + //maxPosG = 0; + //cosAoAAtMaxPosG = 0; + } + + s.pitch = negLim; + debugString.Append($"Limiting Neg Gs"); + debugString.Append(Environment.NewLine); + } + posLim = posPitchDynPresLimitIntegrator * invVesselDynPreskPa + posPitchDynPresLimit; + if (posLim < s.pitch) + { + if (currentG < (maxAllowedGForce * 0.97f * 9.81f)) + { + posPitchDynPresLimitIntegrator += (float)(0.15 * vessel.dynamicPressurekPa); //jsut an override in case things break + + maxPosG = currentG * invVesselDynPreskPa; + cosAoAAtMaxPosG = curCosAoA; + + posPitchDynPresLimit = 0; + + //maxNegG = 0; + //cosAoAAtMaxNegG = 0; + } + + s.pitch = posLim; + debugString.Append($"Limiting Pos Gs"); + debugString.Append(Environment.NewLine); + } + + lastPitchInput = s.pitch; + lastCosAoA = curCosAoA; + + debugString.Append($"Neg Pitch Lim: {negLim}"); + debugString.Append(Environment.NewLine); + debugString.Append($"Pos Pitch Lim: {posLim}"); + debugString.Append(Environment.NewLine); + } + + void CalculateAccelerationAndTurningCircle() + { + maxLiftAcceleration = maxDynPresGRecorded; + maxLiftAcceleration *= (float)vessel.dynamicPressurekPa; //maximum acceleration from lift that the vehicle can provide + + maxLiftAcceleration = Math.Min(maxLiftAcceleration, maxAllowedGForce * 9.81f); //limit it to whichever is smaller, what we can provide or what we can handle + maxLiftAcceleration = maxAllowedGForce * 9.81f; + + if (maxLiftAcceleration > 0) + turnRadius = (float)vessel.Velocity().sqrMagnitude / maxLiftAcceleration; //radius that we can turn in assuming constant velocity, assuming simple circular motion + } + + float MinAltitudeNeeded() //min altitude adjusted for G limits; let's try _not_ to overcook dives and faceplant into the ground + { + //for a pure vertical dive, turnRadius will be the altitude that we need to turn. However, for shallower dives we don't need that much. Let's account for that. + //actual altitude needed will be radius * (1 - cos(theta)), where theta is the angle of the arc from dive entry to the turning circle to the bottom + //we can calculate that from the velocity vector mag dotted with the up vector + + float diveAngleCorrection = -Vector3.Dot(vessel.Velocity() / vessel.srfSpeed, vessel.upAxis); //normalize the vector and dot it with upAxis + //this gives us sin(theta) + if (diveAngleCorrection > 0) //we're headed downwards + { + diveAngleCorrection *= diveAngleCorrection; + diveAngleCorrection = 1 - diveAngleCorrection; + diveAngleCorrection = Math.Max(0f, diveAngleCorrection); //remember to check to make sure numerical errors haven't crept in! Can't have NaN showing up + diveAngleCorrection = Mathf.Sqrt(diveAngleCorrection); //convert sin(theta) to cos(theta) + + diveAngleCorrection = 1 - diveAngleCorrection; //and convert to 1 - cos(theta) + } + else + { + diveAngleCorrection = 0; + } + + return Math.Max(minAltitude, 100 + turnRadius * diveAngleCorrection); + } + + Vector3 DefaultAltPosition() + { + return (vessel.transform.position + (-(float)vessel.altitude * upDirection) + (defaultAltitude * upDirection)); + } + + Vector3 GetSurfacePosition(Vector3 position) + { + return position - ((float)FlightGlobals.getAltitudeAtPos(position) * upDirection); + } + + Vector3 GetTerrainSurfacePosition(Vector3 position) + { + return position - (MissileGuidance.GetRaycastRadarAltitude(position) * upDirection); + } + + Vector3 FlightPosition(Vector3 targetPosition, float minAlt) + { + Vector3 forwardDirection = vesselTransform.up; + Vector3 targetDirection = (targetPosition - vesselTransform.position).normalized; + + float vertFactor = 0; + vertFactor += (((float)vessel.srfSpeed / minSpeed) - 2f) * 0.3f; //speeds greater than 2x minSpeed encourage going upwards; below encourages downwards + vertFactor += (((targetPosition - vesselTransform.position).magnitude / 1000f) - 1f) * 0.3f; //distances greater than 1000m encourage going upwards; closer encourages going downwards + vertFactor -= Mathf.Clamp01(Vector3.Dot(vesselTransform.position - targetPosition, upDirection) / 1600f - 1f) * 0.5f; //being higher than 1600m above a target encourages going downwards + if (targetVessel) + vertFactor += Vector3.Dot(targetVessel.Velocity() / targetVessel.srfSpeed, (targetVessel.ReferenceTransform.position - vesselTransform.position).normalized) * 0.3f; //the target moving away from us encourages upward motion, moving towards us encourages downward motion + else + vertFactor += 0.4f; + vertFactor -= weaponManager.underFire ? 0.5f : 0; //being under fire encourages going downwards as well, to gain energy + + float alt = MissileGuidance.GetRadarAltitude(vessel); + + if (vertFactor > 2) + vertFactor = 2; + if (vertFactor < -2) + vertFactor = -2; + + vertFactor += 0.15f * Mathf.Sin((float)vessel.missionTime * 0.25f); //some randomness in there + + Vector3 projectedDirection = Vector3.ProjectOnPlane(forwardDirection, upDirection); + Vector3 projectedTargetDirection = Vector3.ProjectOnPlane(targetDirection, upDirection); + if (Vector3.Dot(targetDirection, forwardDirection) < 0) + { + if (Vector3.Angle(targetDirection, forwardDirection) > 165f) + { + targetPosition = vesselTransform.position + (Quaternion.AngleAxis(Mathf.Sign(Mathf.Sin((float)vessel.missionTime / 4)) * 45, upDirection) * (projectedDirection.normalized * 200)); + targetDirection = (targetPosition - vesselTransform.position).normalized; + } + + targetPosition = vesselTransform.position + Vector3.Cross(Vector3.Cross(forwardDirection, targetDirection), forwardDirection).normalized * 200; + } + else if (steerMode != SteerModes.Aiming) + { + float distance = (targetPosition - vesselTransform.position).magnitude; + if (vertFactor < 0) + distance = Math.Min(distance, Math.Abs((alt - minAlt) / vertFactor)); + + targetPosition += upDirection * Math.Min(distance, 1000) * vertFactor * Mathf.Clamp01(0.7f - Math.Abs(Vector3.Dot(projectedTargetDirection, projectedDirection))); + } + + if (MissileGuidance.GetRadarAltitude(vessel) > minAlt * 1.1f) + { + return targetPosition; + } + + float pointRadarAlt = MissileGuidance.GetRaycastRadarAltitude(targetPosition); + if (pointRadarAlt < minAlt) + { + float adjustment = (minAlt - pointRadarAlt); + debugString.Append($"Target position is below minAlt. Adjusting by {adjustment}"); + debugString.Append(Environment.NewLine); + return targetPosition + (adjustment * upDirection); + } + else + { + return targetPosition; + } + } + + public override bool IsValidFixedWeaponTarget(Vessel target) + { + if (!vessel) return false; + // aircraft can aim at anything + return true; + } + + bool DetectCollision(Vector3 direction, out Vector3 badDirection) + { + badDirection = Vector3.zero; + if (MissileGuidance.GetRadarAltitude(vessel) < 20) return false; + + direction = direction.normalized; + int layerMask = 1 << 15; + Ray ray = new Ray(vesselTransform.position + (50 * vesselTransform.up), direction); + float distance = Mathf.Clamp((float)vessel.srfSpeed * 4f, 125f, 2500); + RaycastHit hit; + if (!Physics.SphereCast(ray, 10, out hit, distance, layerMask)) return false; + Rigidbody otherRb = hit.collider.attachedRigidbody; + if (otherRb) + { + if (!(Vector3.Dot(otherRb.velocity, vessel.Velocity()) < 0)) return false; + badDirection = hit.point - ray.origin; + return true; + } + badDirection = hit.point - ray.origin; + return true; + } + + void UpdateCommand(FlightCtrlState s) + { + if (command == PilotCommands.Follow && !commandLeader) + { + ReleaseCommand(); + return; + } + + if (command == PilotCommands.Follow) + { + currentStatus = "Follow"; + UpdateFollowCommand(s); + } + else if (command == PilotCommands.FlyTo) + { + currentStatus = "Fly To"; + FlyOrbit(s, assignedPositionGeo, 2500, idleSpeed, ClockwiseOrbit); + } + else if (command == PilotCommands.Attack) + { + currentStatus = "Attack"; + FlyOrbit(s, assignedPositionGeo, 4500, maxSpeed, ClockwiseOrbit); + } + } + + void UpdateFollowCommand(FlightCtrlState s) + { + steerMode = SteerModes.NormalFlight; + vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, false); + + commandSpeed = commandLeader.vessel.srfSpeed; + commandHeading = commandLeader.vessel.Velocity().normalized; + + //formation position + Vector3d commandPosition = GetFormationPosition(); + debugFollowPosition = commandPosition; + + float distanceToPos = Vector3.Distance(vesselTransform.position, commandPosition); + + float dotToPos = Vector3.Dot(vesselTransform.up, commandPosition - vesselTransform.position); + Vector3 flyPos; + useRollHint = false; + + float ctrlModeThresh = 1000; + + if (distanceToPos < ctrlModeThresh) + { + flyPos = commandPosition + (ctrlModeThresh * commandHeading); + + Vector3 vectorToFlyPos = flyPos - vessel.ReferenceTransform.position; + Vector3 projectedPosOffset = Vector3.ProjectOnPlane(commandPosition - vessel.ReferenceTransform.position, commandHeading); + float posOffsetMag = projectedPosOffset.magnitude; + float adjustAngle = (Mathf.Clamp(posOffsetMag * 0.27f, 0, 25)); + Vector3 projVel = Vector3.Project(vessel.Velocity() - commandLeader.vessel.Velocity(), projectedPosOffset); + adjustAngle -= Mathf.Clamp(Mathf.Sign(Vector3.Dot(projVel, projectedPosOffset)) * projVel.magnitude * 0.12f, -10, 10); + + adjustAngle *= Mathf.Deg2Rad; + + vectorToFlyPos = Vector3.RotateTowards(vectorToFlyPos, projectedPosOffset, adjustAngle, 0); + + flyPos = vessel.ReferenceTransform.position + vectorToFlyPos; + + if (distanceToPos < 400) + { + steerMode = SteerModes.Aiming; + } + else + { + steerMode = SteerModes.NormalFlight; + } + + if (distanceToPos < 10) + { + useRollHint = true; + } + } + else + { + steerMode = SteerModes.NormalFlight; + flyPos = commandPosition; + } + + double finalMaxSpeed = commandSpeed; + if (dotToPos > 0) + { + finalMaxSpeed += (distanceToPos / 8); + } + else + { + finalMaxSpeed -= (distanceToPos / 2); + } + + AdjustThrottle((float)finalMaxSpeed, true); + + FlyToPosition(s, flyPos); + } + + Vector3d GetFormationPosition() + { + Quaternion origVRot = velocityTransform.rotation; + Vector3 origVLPos = velocityTransform.localPosition; + + velocityTransform.position = commandLeader.vessel.ReferenceTransform.position; + if (commandLeader.vessel.Velocity() != Vector3d.zero) + { + velocityTransform.rotation = Quaternion.LookRotation(commandLeader.vessel.Velocity(), upDirection); + velocityTransform.rotation = Quaternion.AngleAxis(90, velocityTransform.right) * velocityTransform.rotation; + } + else + { + velocityTransform.rotation = commandLeader.vessel.ReferenceTransform.rotation; + } + + Vector3d pos = velocityTransform.TransformPoint(this.GetLocalFormationPosition(commandFollowIndex));// - lateralVelVector - verticalVelVector; + + velocityTransform.localPosition = origVLPos; + velocityTransform.rotation = origVRot; + + return pos; + } + + public override void CommandTakeOff() + { + base.CommandTakeOff(); + standbyMode = false; + } + + protected override void OnGUI() + { + base.OnGUI(); + + if (!pilotEnabled || !vessel.isActiveVessel) return; + + if (!BDArmorySettings.DRAW_DEBUG_LINES) return; + if (command == PilotCommands.Follow) + { + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, debugFollowPosition, 2, Color.red); + } + + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, debugPos, 5, Color.red); + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, vesselTransform.position + vesselTransform.up * 5000, 3, Color.white); + + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, vesselTransform.position + rollTarget, 2, Color.blue); + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position + (0.05f * vesselTransform.right), vesselTransform.position + (0.05f * vesselTransform.right) + angVelRollTarget, 2, Color.green); + } + } +} diff --git a/BDArmory/Modules/BDModuleSurfaceAI.cs b/BDArmory/Modules/BDModuleSurfaceAI.cs new file mode 100644 index 000000000..f766293df --- /dev/null +++ b/BDArmory/Modules/BDModuleSurfaceAI.cs @@ -0,0 +1,709 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using BDArmory.Control; +using BDArmory.Core; +using BDArmory.Misc; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class BDModuleSurfaceAI : BDGenericAIBase, IBDAIControl + { + #region Declarations + + Vessel extendingTarget = null; + Vessel bypassTarget = null; + Vector3 bypassTargetPos; + + Vector3 targetDirection; + float targetVelocity; // the velocity the ship should target, not the velocity of its target + bool aimingMode = false; + + int collisionDetectionTicker = 0; + Vector3? dodgeVector; + float weaveAdjustment = 0; + float weaveDirection = 1; + const float weaveLimit = 15; + const float weaveFactor = 6.5f; + + Vector3 upDir; + + AIUtils.TraversabilityMatrix pathingMatrix; + List waypoints = new List(); + bool leftPath = false; + + protected override Vector3d assignedPositionGeo + { + get { return intermediatePositionGeo; } + set + { + finalPositionGeo = value; + leftPath = true; + } + } + + Vector3d finalPositionGeo; + Vector3d intermediatePositionGeo; + public override Vector3d commandGPS => finalPositionGeo; + + private BDLandSpeedControl motorControl; + + //settings + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_VehicleType"),//Vehicle type + UI_ChooseOption(options = new string[3] { "Land", "Amphibious", "Water" })] + public string SurfaceTypeName = "Land"; + + public AIUtils.VehicleMovementType SurfaceType + => (AIUtils.VehicleMovementType)Enum.Parse(typeof(AIUtils.VehicleMovementType), SurfaceTypeName); + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxSlopeAngle"),//Max slope angle + UI_FloatRange(minValue = 1f, maxValue = 30f, stepIncrement = 1f, scene = UI_Scene.All)] + public float MaxSlopeAngle = 10f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_CruiseSpeed"),//Cruise speed + UI_FloatRange(minValue = 5f, maxValue = 60f, stepIncrement = 1f, scene = UI_Scene.All)] + public float CruiseSpeed = 20; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxSpeed"),//Max speed + UI_FloatRange(minValue = 5f, maxValue = 80f, stepIncrement = 1f, scene = UI_Scene.All)] + public float MaxSpeed = 30; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxDrift"),//Max drift + UI_FloatRange(minValue = 1f, maxValue = 180f, stepIncrement = 1f, scene = UI_Scene.All)] + public float MaxDrift = 10; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_TargetPitch"),//Moving pitch + UI_FloatRange(minValue = -10f, maxValue = 10f, stepIncrement = .1f, scene = UI_Scene.All)] + public float TargetPitch = 0; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_BankAngle"),//Bank angle + UI_FloatRange(minValue = -45f, maxValue = 45f, stepIncrement = 1f, scene = UI_Scene.All)] + public float BankAngle = 0; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerFactor"),//Steer Factor + UI_FloatRange(minValue = 0.2f, maxValue = 20f, stepIncrement = .1f, scene = UI_Scene.All)] + public float steerMult = 6; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_SteerDamping"),//Steer Damping + UI_FloatRange(minValue = 0.1f, maxValue = 10f, stepIncrement = .1f, scene = UI_Scene.All)] + public float steerDamping = 3; + + //[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Steering"), + // UI_Toggle(enabledText = "Powered", disabledText = "Passive")] + public bool PoweredSteering = true; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_BroadsideAttack"),//Attack vector + UI_Toggle(enabledText = "#LOC_BDArmory_BroadsideAttack_enabledText", disabledText = "#LOC_BDArmory_BroadsideAttack_disabledText")]//Broadside--Bow + public bool BroadsideAttack = false; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MinEngagementRange"),//Min engagement range + UI_FloatRange(minValue = 0f, maxValue = 6000f, stepIncrement = 100f, scene = UI_Scene.All)] + public float MinEngagementRange = 500; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxEngagementRange"),//Max engagement range + UI_FloatRange(minValue = 500f, maxValue = 8000f, stepIncrement = 100f, scene = UI_Scene.All)] + public float MaxEngagementRange = 4000; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_ManeuverRCS"),//RCS active + UI_Toggle(enabledText = "#LOC_BDArmory_ManeuverRCS_enabledText", disabledText = "#LOC_BDArmory_ManeuverRCS_disabledText", scene = UI_Scene.All),]//Maneuvers--Combat + public bool ManeuverRCS = false; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MinObstacleMass", advancedTweakable = true),//Min obstacle mass + UI_FloatRange(minValue = 0f, maxValue = 100f, stepIncrement = 1f, scene = UI_Scene.All),] + public float AvoidMass = 0f; + + [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_PreferredBroadsideDirection", advancedTweakable = true),//Preferred broadside direction + UI_ChooseOption(options = new string[3] { "Starboard", "Whatever", "Port" }, scene = UI_Scene.All),] + public string OrbitDirectionName = "Whatever"; + readonly string[] orbitDirections = new string[3] { "Starboard", "Whatever", "Port" }; + + [KSPField(isPersistant = true)] + int sideSlipDirection = 0; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_GoesUp", advancedTweakable = true),//Goes up to + UI_Toggle(enabledText = "#LOC_BDArmory_GoesUp_enabledText", disabledText = "#LOC_BDArmory_GoesUp_disabledText", scene = UI_Scene.All),]//eleven--ten + public bool UpToEleven = false; + bool toEleven = false; + + const float AttackAngleAtMaxRange = 30f; + + Dictionary altMaxValues = new Dictionary + { + { nameof(MaxSlopeAngle), 90f }, + { nameof(CruiseSpeed), 300f }, + { nameof(MaxSpeed), 400f }, + { nameof(steerMult), 200f }, + { nameof(steerDamping), 100f }, + { nameof(MinEngagementRange), 20000f }, + { nameof(MaxEngagementRange), 30000f }, + { nameof(AvoidMass), 1000000f }, + }; + + #endregion Declarations + + #region RMB info in editor + + // Yes + public override string GetInfo() + { + // known bug - the game caches the RMB info, changing the variable after checking the info + // does not update the info. :( No idea how to force an update. + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Available settings:"); + sb.AppendLine($"- Vehicle type - can this vessel operate on land/sea/both"); + sb.AppendLine($"- Max slope angle - what is the steepest slope this vessel can negotiate"); + sb.AppendLine($"- Cruise speed - the default speed at which it is safe to maneuver"); + sb.AppendLine($"- Max speed - the maximum combat speed"); + sb.AppendLine($"- Max drift - maximum allowed angle between facing and velocity vector"); + sb.AppendLine($"- Moving pitch - the pitch level to maintain when moving at cruise speed"); + sb.AppendLine($"- Bank angle - the limit on roll when turning, positive rolls into turns"); + sb.AppendLine($"- Steer Factor - higher will make the AI apply more control input for the same desired rotation"); + sb.AppendLine($"- Steer Damping - higher will make the AI apply more control input when it wants to stop rotation"); + sb.AppendLine($"- Attack vector - does the vessel attack from the front or the sides"); + sb.AppendLine($"- Min engagement range - AI will try to move away from oponents if closer than this range"); + sb.AppendLine($"- Max engagement range - AI will prioritize getting closer over attacking when beyond this range"); + sb.AppendLine($"- RCS active - Use RCS during any maneuvers, or only in combat "); + if (GameSettings.ADVANCED_TWEAKABLES) + { + sb.AppendLine($"- Min obstacle mass - Obstacles of a lower mass than this will be ignored instead of avoided"); + sb.AppendLine($"- Goes up to - Increases variable limits, no direct effect on behaviour"); + } + + return sb.ToString(); + } + + #endregion RMB info in editor + + #region events + + public override void ActivatePilot() + { + base.ActivatePilot(); + + pathingMatrix = new AIUtils.TraversabilityMatrix(); + + if (!motorControl) + { + motorControl = gameObject.AddComponent(); + motorControl.vessel = vessel; + } + motorControl.Activate(); + + if (BroadsideAttack && sideSlipDirection == 0) + { + sideSlipDirection = orbitDirections.IndexOf(OrbitDirectionName); + if (sideSlipDirection == 0) + sideSlipDirection = UnityEngine.Random.Range(0, 2) > 1 ? 1 : -1; + } + + leftPath = true; + extendingTarget = null; + bypassTarget = null; + collisionDetectionTicker = 6; + } + + public override void DeactivatePilot() + { + base.DeactivatePilot(); + + if (motorControl) + motorControl.Deactivate(); + } + + void Update() + { + // switch up the alt values if up to eleven is toggled + if (UpToEleven != toEleven) + { + using (var s = altMaxValues.Keys.ToList().GetEnumerator()) + while (s.MoveNext()) + { + UI_FloatRange euic = (UI_FloatRange) + (HighLogic.LoadedSceneIsFlight ? Fields[s.Current].uiControlFlight : Fields[s.Current].uiControlEditor); + float tempValue = euic.maxValue; + euic.maxValue = altMaxValues[s.Current]; + altMaxValues[s.Current] = tempValue; + // change the value back to what it is now after fixed update, because changing the max value will clamp it down + // using reflection here, don't look at me like that, this does not run often + StartCoroutine(setVar(s.Current, (float)typeof(BDModuleSurfaceAI).GetField(s.Current).GetValue(this))); + } + toEleven = UpToEleven; + } + } + + IEnumerator setVar(string name, float value) + { + yield return new WaitForFixedUpdate(); + typeof(BDModuleSurfaceAI).GetField(name).SetValue(this, value); + } + + protected override void OnGUI() + { + base.OnGUI(); + + if (!pilotEnabled || !vessel.isActiveVessel) return; + + if (!BDArmorySettings.DRAW_DEBUG_LINES) return; + if (command == PilotCommands.Follow) + { + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, assignedPositionWorld, 2, Color.red); + } + + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, vesselTransform.position + targetDirection * 10f, 2, Color.blue); + BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position + (0.05f * vesselTransform.right), vesselTransform.position + (0.05f * vesselTransform.right), 2, Color.green); + + pathingMatrix.DrawDebug(vessel.CoM, waypoints); + } + + #endregion events + + #region Actual AI Pilot + + protected override void AutoPilot(FlightCtrlState s) + { + if (!vessel.Autopilot.Enabled) + vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, true); + + targetVelocity = 0; + targetDirection = vesselTransform.up; + aimingMode = false; + upDir = VectorUtils.GetUpDirection(vesselTransform.position); + DebugLine(""); + + // check if we should be panicking + if (!PanicModes()) + { + // pilot logic figures out what we're supposed to be doing, and sets the base state + PilotLogic(); + // situational awareness modifies the base as best as it can (evasive mainly) + Tactical(); + } + + AttitudeControl(s); // move according to our targets + AdjustThrottle(targetVelocity); // set throttle according to our targets and movement + } + + void PilotLogic() + { + // check for collisions, but not every frame + if (collisionDetectionTicker == 0) + { + collisionDetectionTicker = 20; + float predictMult = Mathf.Clamp(10 / MaxDrift, 1, 10); + + dodgeVector = null; + + using (var vs = BDATargetManager.LoadedVessels.GetEnumerator()) + while (vs.MoveNext()) + { + if (vs.Current == null || vs.Current == vessel) continue; + if (!vs.Current.LandedOrSplashed || vs.Current.FindPartModuleImplementing()?.commandLeader?.vessel == vessel + || vs.Current.GetTotalMass() < AvoidMass) + continue; + dodgeVector = PredictCollisionWithVessel(vs.Current, 5f * predictMult, 0.5f); + if (dodgeVector != null) break; + } + } + else + collisionDetectionTicker--; + + // avoid collisions if any are found + if (dodgeVector != null) + { + targetVelocity = PoweredSteering ? MaxSpeed : CruiseSpeed; + targetDirection = (Vector3)dodgeVector; + SetStatus($"Avoiding Collision"); + leftPath = true; + return; + } + + // if bypass target is no longer relevant, remove it + if (bypassTarget != null && ((bypassTarget != targetVessel && bypassTarget != commandLeader?.vessel) + || (VectorUtils.GetWorldSurfacePostion(bypassTargetPos, vessel.mainBody) - bypassTarget.CoM).sqrMagnitude > 500000)) + { + bypassTarget = null; + } + + if (bypassTarget == null) + { + // check for enemy targets and engage + // not checking for guard mode, because if guard mode is off now you can select a target manually and if it is of opposing team, the AI will try to engage while you can man the turrets + if (weaponManager && targetVessel != null && !BDArmorySettings.PEACE_MODE) + { + leftPath = true; + if (collisionDetectionTicker == 5) + checkBypass(targetVessel); + + Vector3 vecToTarget = targetVessel.CoM - vessel.CoM; + float distance = vecToTarget.magnitude; + // lead the target a bit, where 1km/s is a ballpark estimate of the average bullet velocity + float shotSpeed = 1000f; + if (weaponManager?.selectedWeapon is ModuleWeapon wep) + shotSpeed = wep.bulletVelocity; + vecToTarget = targetVessel.PredictPosition(distance / shotSpeed) - vessel.CoM; + + if (BroadsideAttack) + { + Vector3 sideVector = Vector3.Cross(vecToTarget, upDir); //find a vector perpendicular to direction to target + if (collisionDetectionTicker == 10 + && !pathingMatrix.TraversableStraightLine( + VectorUtils.WorldPositionToGeoCoords(vessel.CoM, vessel.mainBody), + VectorUtils.WorldPositionToGeoCoords(vessel.PredictPosition(10), vessel.mainBody), + vessel.mainBody, SurfaceType, MaxSlopeAngle, AvoidMass)) + sideSlipDirection = -Math.Sign(Vector3.Dot(vesselTransform.up, sideVector)); // switch sides if we're running ashore + sideVector *= sideSlipDirection; + + float sidestep = distance >= MaxEngagementRange ? Mathf.Clamp01((MaxEngagementRange - distance) / (CruiseSpeed * Mathf.Clamp(90 / MaxDrift, 0, 10)) + 1) * AttackAngleAtMaxRange / 90 : // direct to target to attackAngle degrees if over maxrange + (distance <= MinEngagementRange ? 1.5f - distance / (MinEngagementRange * 2) : // 90 to 135 degrees if closer than minrange + (MaxEngagementRange - distance) / (MaxEngagementRange - MinEngagementRange) * (1 - AttackAngleAtMaxRange / 90) + AttackAngleAtMaxRange / 90); // attackAngle to 90 degrees from maxrange to minrange + targetDirection = Vector3.LerpUnclamped(vecToTarget.normalized, sideVector.normalized, sidestep); // interpolate between the side vector and target direction vector based on sidestep + targetVelocity = MaxSpeed; + DebugLine($"Broadside attack angle {sidestep}"); + } + else // just point at target and go + { + if ((targetVessel.horizontalSrfSpeed < 10 || Vector3.Dot(Vector3.ProjectOnPlane(targetVessel.srf_vel_direction, upDir), vessel.up) < 0) //if target is stationary or we're facing in opposite directions + && (distance < MinEngagementRange || (distance < (MinEngagementRange * 3 + MaxEngagementRange) / 4 //and too close together + && extendingTarget != null && targetVessel != null && extendingTarget == targetVessel))) + { + extendingTarget = targetVessel; + // not sure if this part is very smart, potential for improvement + targetDirection = -vecToTarget; //extend + targetVelocity = MaxSpeed; + SetStatus($"Extending"); + return; + } + else + { + extendingTarget = null; + targetDirection = Vector3.ProjectOnPlane(vecToTarget, upDir); + if (Vector3.Dot(targetDirection, vesselTransform.up) < 0) + targetVelocity = PoweredSteering ? MaxSpeed : 0; // if facing away from target + else if (distance >= MaxEngagementRange || distance <= MinEngagementRange) + targetVelocity = MaxSpeed; + else + { + targetVelocity = CruiseSpeed / 10 + (MaxSpeed - CruiseSpeed / 10) * (distance - MinEngagementRange) / (MaxEngagementRange - MinEngagementRange); //slow down if inside engagement range to extend shooting opportunities + switch (weaponManager?.selectedWeapon?.GetWeaponClass()) + { + case WeaponClasses.Gun: + case WeaponClasses.DefenseLaser: + var gun = (ModuleWeapon)weaponManager.selectedWeapon; + if ((gun.yawRange == 0 || gun.maxPitch == gun.minPitch) && gun.FiringSolutionVector != null) + { + aimingMode = true; + if (Vector3.Angle((Vector3)gun.FiringSolutionVector, vessel.transform.up) < 20) + targetDirection = (Vector3)gun.FiringSolutionVector; + } + break; + + case WeaponClasses.Rocket: + var rocket = (RocketLauncher)weaponManager.selectedWeapon; + if (rocket.yawRange == 0 || rocket.maxPitch == rocket.minPitch) + { + aimingMode = true; + if (Vector3.Angle((Vector3)rocket.FiringSolutionVector, vessel.transform.up) < 20) + targetDirection = (Vector3)rocket.FiringSolutionVector; + } + break; + } + } + targetVelocity = Mathf.Clamp(targetVelocity, PoweredSteering ? CruiseSpeed / 5 : 0, MaxSpeed); // maintain a bit of speed if using powered steering + } + } + SetStatus($"Engaging target"); + return; + } + + // follow + if (command == PilotCommands.Follow) + { + leftPath = true; + if (collisionDetectionTicker == 5) + checkBypass(commandLeader.vessel); + + Vector3 targetPosition = GetFormationPosition(); + Vector3 targetDistance = targetPosition - vesselTransform.position; + if (Vector3.Dot(targetDistance, vesselTransform.up) < 0 + && Vector3.ProjectOnPlane(targetDistance, upDir).sqrMagnitude < 250f * 250f + && Vector3.Angle(vesselTransform.up, commandLeader.vessel.srf_velocity) < 0.8f) + { + targetDirection = Vector3.RotateTowards(Vector3.ProjectOnPlane(commandLeader.vessel.srf_vel_direction, upDir), targetDistance, 0.2f, 0); + } + else + { + targetDirection = Vector3.ProjectOnPlane(targetDistance, upDir); + } + targetVelocity = (float)(commandLeader.vessel.horizontalSrfSpeed + (vesselTransform.position - targetPosition).magnitude / 15); + if (Vector3.Dot(targetDirection, vesselTransform.up) < 0 && !PoweredSteering) targetVelocity = 0; + SetStatus($"Following"); + return; + } + } + + // goto + if (leftPath && bypassTarget == null) + { + Pathfind(finalPositionGeo); + leftPath = false; + } + + const float targetRadius = 250f; + targetDirection = Vector3.ProjectOnPlane(assignedPositionWorld - vesselTransform.position, upDir); + + if (targetDirection.sqrMagnitude > targetRadius * targetRadius) + { + if (bypassTarget != null) + targetVelocity = MaxSpeed; + else if (waypoints.Count > 1) + targetVelocity = command == PilotCommands.Attack ? MaxSpeed : CruiseSpeed; + else + targetVelocity = Mathf.Clamp((targetDirection.magnitude - targetRadius / 2) / 5f, + 0, command == PilotCommands.Attack ? MaxSpeed : CruiseSpeed); + + if (Vector3.Dot(targetDirection, vesselTransform.up) < 0 && !PoweredSteering) targetVelocity = 0; + SetStatus(bypassTarget ? "Repositioning" : "Moving"); + return; + } + + cycleWaypoint(); + + SetStatus($"Not doing anything in particular"); + targetDirection = vesselTransform.up; + } + + void Tactical() + { + // enable RCS if we're in combat + vessel.ActionGroups.SetGroup(KSPActionGroup.RCS, weaponManager && targetVessel && !BDArmorySettings.PEACE_MODE + && (weaponManager.selectedWeapon != null || (vessel.CoM - targetVessel.CoM).sqrMagnitude < MaxEngagementRange * MaxEngagementRange) + || weaponManager.underFire || weaponManager.missileIsIncoming); + + // if weaponManager thinks we're under fire, do the evasive dance + if (weaponManager.underFire || weaponManager.missileIsIncoming) + { + targetVelocity = MaxSpeed; + if (weaponManager.underFire || weaponManager.incomingMissileDistance < 2500) + { + if (Mathf.Abs(weaveAdjustment) + Time.deltaTime * weaveFactor > weaveLimit) weaveDirection *= -1; + weaveAdjustment += weaveFactor * weaveDirection * Time.deltaTime; + } + else + { + weaveAdjustment = 0; + } + } + else + { + weaveAdjustment = 0; + } + DebugLine($"underFire {weaponManager.underFire}, weaveAdjustment {weaveAdjustment}"); + } + + bool PanicModes() + { + if (!vessel.LandedOrSplashed) + { + targetVelocity = 0; + targetDirection = Vector3.ProjectOnPlane(vessel.srf_velocity, upDir); + SetStatus("Airtime!"); + return true; + } + else if (vessel.Landed + && !vessel.Splashed // I'm looking at you, Kerbal Konstructs. (When launching directly into water, KK seems to set both vessel.Landed and vessel.Splashed to true.) + && (SurfaceType & AIUtils.VehicleMovementType.Land) == 0) + { + targetVelocity = 0; + SetStatus("Stranded"); + return true; + } + else if (vessel.Splashed && (SurfaceType & AIUtils.VehicleMovementType.Water) == 0) + { + targetVelocity = 0; + SetStatus("Floating"); + return true; + } + return false; + } + + void AdjustThrottle(float targetSpeed) + { + targetVelocity = Mathf.Clamp(targetVelocity, 0, MaxSpeed); + + if (float.IsNaN(targetSpeed)) //because yeah, I might have left division by zero in there somewhere + { + targetSpeed = CruiseSpeed; + DebugLine("Target velocity NaN, set to CruiseSpeed."); + } + else + DebugLine($"Target velocity: {targetVelocity}"); + DebugLine($"engine thrust: {speedController.debugThrust}, motor zero: {motorControl.zeroPoint}"); + + speedController.targetSpeed = motorControl.targetSpeed = targetSpeed; + speedController.useBrakes = motorControl.preventNegativeZeroPoint = speedController.debugThrust > 0; + } + + void AttitudeControl(FlightCtrlState s) + { + const float terrainOffset = 5; + + Vector3 yawTarget = Vector3.ProjectOnPlane(targetDirection, vesselTransform.forward); + + // limit "aoa" if we're moving + float driftMult = 1; + if (vessel.horizontalSrfSpeed * 10 > CruiseSpeed) + { + driftMult = Mathf.Max(Vector3.Angle(vessel.srf_velocity, yawTarget) / MaxDrift, 1); + yawTarget = Vector3.RotateTowards(vessel.srf_velocity, yawTarget, MaxDrift * Mathf.Deg2Rad, 0); + } + + float yawError = VectorUtils.SignedAngle(vesselTransform.up, yawTarget, vesselTransform.right) + (aimingMode ? 0 : weaveAdjustment); + DebugLine($"yaw target: {yawTarget}, yaw error: {yawError}"); + DebugLine($"drift multiplier: {driftMult}"); + + Vector3 baseForward = vessel.transform.up * terrainOffset; + float basePitch = Mathf.Atan2( + AIUtils.GetTerrainAltitude(vessel.CoM + baseForward, vessel.mainBody, false) + - AIUtils.GetTerrainAltitude(vessel.CoM - baseForward, vessel.mainBody, false), + terrainOffset * 2) * Mathf.Rad2Deg; + float pitchAngle = basePitch + TargetPitch * Mathf.Clamp01((float)vessel.horizontalSrfSpeed / CruiseSpeed); + if (aimingMode) + pitchAngle = VectorUtils.SignedAngle(vesselTransform.up, Vector3.ProjectOnPlane(targetDirection, vesselTransform.right), -vesselTransform.forward); + DebugLine($"terrain fw slope: {basePitch}, target pitch: {pitchAngle}"); + + float pitch = 90 - Vector3.Angle(vesselTransform.up, upDir); + float pitchError = pitchAngle - pitch; + + Vector3 baseLateral = vessel.transform.right * terrainOffset; + float baseRoll = Mathf.Atan2( + AIUtils.GetTerrainAltitude(vessel.CoM + baseLateral, vessel.mainBody, false) + - AIUtils.GetTerrainAltitude(vessel.CoM - baseLateral, vessel.mainBody, false), + terrainOffset * 2) * Mathf.Rad2Deg; + float drift = VectorUtils.SignedAngle(vesselTransform.up, Vector3.ProjectOnPlane(vessel.GetSrfVelocity(), upDir), vesselTransform.right); + float bank = VectorUtils.SignedAngle(-vesselTransform.forward, upDir, -vesselTransform.right); + float targetRoll = baseRoll + BankAngle * Mathf.Clamp01(drift / MaxDrift) * Mathf.Clamp01((float)vessel.srfSpeed / CruiseSpeed); + float rollError = targetRoll - bank; + DebugLine($"terrain sideways slope: {baseRoll}, target roll: {targetRoll}"); + + Vector3 localAngVel = vessel.angularVelocity; + s.roll = steerMult * 0.006f * rollError - 0.4f * steerDamping * -localAngVel.y; + s.pitch = ((aimingMode ? 0.02f : 0.015f) * steerMult * pitchError) - (steerDamping * -localAngVel.x); + s.yaw = (((aimingMode ? 0.007f : 0.005f) * steerMult * yawError) - (steerDamping * 0.2f * -localAngVel.z)) * driftMult; + s.wheelSteer = -(((aimingMode ? 0.005f : 0.003f) * steerMult * yawError) - (steerDamping * 0.1f * -localAngVel.z)); + + if (ManeuverRCS && (Mathf.Abs(s.roll) >= 1 || Mathf.Abs(s.pitch) >= 1 || Mathf.Abs(s.yaw) >= 1)) + vessel.ActionGroups.SetGroup(KSPActionGroup.RCS, true); + } + + #endregion Actual AI Pilot + + #region Autopilot helper functions + + public override bool CanEngage() + { + if (vessel.Splashed && (SurfaceType & AIUtils.VehicleMovementType.Water) == 0) + DebugLine(vessel.vesselName + " cannot engage: boat not in water"); + else if (vessel.Landed && (SurfaceType & AIUtils.VehicleMovementType.Land) == 0) + DebugLine(vessel.vesselName + " cannot engage: vehicle not on land"); + else if (!vessel.LandedOrSplashed) + DebugLine(vessel.vesselName + " cannot engage: vessel not on surface"); + // the motorControl part fails sometimes, and guard mode then decides not to select a weapon + // figure out what is wrong with motor control before uncommenting :D + //else if (speedController.debugThrust + (motorControl?.MaxAccel ?? 0) <= 0) + // DebugLine(vessel.vesselName + " cannot engage: no engine power"); + else + return true; + return false; + } + + public override bool IsValidFixedWeaponTarget(Vessel target) + => !BroadsideAttack && + (((target?.Splashed ?? false) && (SurfaceType & AIUtils.VehicleMovementType.Water) != 0) + || ((target?.Landed ?? false) && (SurfaceType & AIUtils.VehicleMovementType.Land) != 0)) + ; //valid if can traverse the same medium and using bow fire + + /// null if no collision, dodge vector if one detected + Vector3? PredictCollisionWithVessel(Vessel v, float maxTime, float interval) + { + //evasive will handle avoiding missiles + if (v == weaponManager.incomingMissileVessel + || v.rootPart.FindModuleImplementing() != null) + return null; + + float time = Mathf.Min(0.5f, maxTime); + while (time < maxTime) + { + Vector3 tPos = v.PredictPosition(time); + Vector3 myPos = vessel.PredictPosition(time); + if (Vector3.SqrMagnitude(tPos - myPos) < 2500f) + { + return Vector3.Dot(tPos - myPos, vesselTransform.right) > 0 ? -vesselTransform.right : vesselTransform.right; + } + + time = Mathf.MoveTowards(time, maxTime, interval); + } + + return null; + } + + void checkBypass(Vessel target) + { + if (!pathingMatrix.TraversableStraightLine( + VectorUtils.WorldPositionToGeoCoords(vessel.CoM, vessel.mainBody), + VectorUtils.WorldPositionToGeoCoords(target.CoM, vessel.mainBody), + vessel.mainBody, SurfaceType, MaxSlopeAngle, AvoidMass)) + { + bypassTarget = target; + bypassTargetPos = VectorUtils.WorldPositionToGeoCoords(target.CoM, vessel.mainBody); + waypoints = pathingMatrix.Pathfind( + VectorUtils.WorldPositionToGeoCoords(vessel.CoM, vessel.mainBody), + VectorUtils.WorldPositionToGeoCoords(target.CoM, vessel.mainBody), + vessel.mainBody, SurfaceType, MaxSlopeAngle, AvoidMass); + if (VectorUtils.GeoDistance(waypoints[waypoints.Count - 1], bypassTargetPos, vessel.mainBody) < 200) + waypoints.RemoveAt(waypoints.Count - 1); + if (waypoints.Count > 0) + intermediatePositionGeo = waypoints[0]; + else + bypassTarget = null; + } + } + + private void Pathfind(Vector3 destination) + { + waypoints = pathingMatrix.Pathfind( + VectorUtils.WorldPositionToGeoCoords(vessel.CoM, vessel.mainBody), + destination, vessel.mainBody, SurfaceType, MaxSlopeAngle, AvoidMass); + intermediatePositionGeo = waypoints[0]; + } + + void cycleWaypoint() + { + if (waypoints.Count > 1) + { + waypoints.RemoveAt(0); + intermediatePositionGeo = waypoints[0]; + } + else if (bypassTarget != null) + { + waypoints.Clear(); + bypassTarget = null; + leftPath = true; + } + } + + #endregion Autopilot helper functions + + #region WingCommander + + Vector3 GetFormationPosition() + { + return commandLeader.vessel.CoM + Quaternion.LookRotation(commandLeader.vessel.up, upDir) * this.GetLocalFormationPosition(commandFollowIndex); + } + + #endregion WingCommander + } +} diff --git a/BDArmory/Modules/BDRotaryRail.cs b/BDArmory/Modules/BDRotaryRail.cs new file mode 100644 index 000000000..d6e2e49ed --- /dev/null +++ b/BDArmory/Modules/BDRotaryRail.cs @@ -0,0 +1,822 @@ +using System.Collections; +using System.Collections.Generic; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class BDRotaryRail : PartModule + { + [KSPField] public float maxLength; + + [KSPField] public float maxHeight; + + [KSPField] public int intervals; + + [KSPField] public float rotationSpeed = 360; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_Rails")]//Rails + public float + numberOfRails = 8; + + float railAngle; + + [KSPField] public float rotationDelay = 0.15f; + + [KSPField(isPersistant = true)] public int railIndex; + + Dictionary missileToRailIndex; + Dictionary railToMissileIndex; + + [KSPField(isPersistant = true)] public float currentHeight; + + [KSPField(isPersistant = true)] public float currentLength; + + public int missileCount; + MissileLauncher[] missileChildren; + Transform[] missileTransforms; + Transform[] missileReferenceTransforms; + + Dictionary comOffsets; + + float lengthInterval; + float heightInterval; + + List rotationTransforms; + List heightTransforms; + List lengthTransforms; + List rails; + int[] railCounts = new int[] { 2, 3, 4, 6, 8 }; + + [KSPField(isPersistant = true)] public float railCountIndex = 4; + + bool rdyToFire; + + public bool readyToFire + { + get { return rdyToFire; } + } + + public MissileLauncher nextMissile; + + MissileLauncher rdyMissile; + + public MissileLauncher readyMissile + { + get { return rdyMissile; } + } + + MissileFire wm; + + public MissileFire weaponManager + { + get + { + if (wm && wm.vessel == vessel) return wm; + wm = null; + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + wm = mf.Current; + break; + } + mf.Dispose(); + return wm; + } + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_RailsPlus")]//Rails++ + public void RailsPlus() + { + IncreaseRails(true); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_RailsMinus")]//Rails-- + public void RailsMinus() + { + DecreaseRails(true); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_IncreaseHeight")]//Height++ + public void HeightPlus() + { + IncreaseHeight(true); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DecreaseHeight")]//Height-- + public void HeightMinus() + { + DecreaseHeight(true); + } + + public void IncreaseHeight(bool updateSym) + { + float prevHeight = currentHeight; + currentHeight = Mathf.Min(currentHeight + heightInterval, maxHeight); + + UpdateChildrenHeight(currentHeight - prevHeight); + UpdateModelState(); + + if (!updateSym) return; + List.Enumerator p = part.symmetryCounterparts.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + if (p.Current != part) + { + p.Current.FindModuleImplementing().IncreaseHeight(false); + } + } + p.Dispose(); + } + + public void DecreaseHeight(bool updateSym) + { + float prevHeight = currentHeight; + currentHeight = Mathf.Max(currentHeight - heightInterval, 0); + + UpdateChildrenHeight(currentHeight - prevHeight); + UpdateModelState(); + + if (!updateSym) return; + List.Enumerator p = part.symmetryCounterparts.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + if (p.Current != part) + { + p.Current.FindModuleImplementing().DecreaseHeight(false); + } + } + p.Dispose(); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_IncreaseLength")]//Length++ + public void LengthPlus() + { + IncreaseLength(true); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DecreaseLength")]//Length-- + public void LengthMinus() + { + DecreaseLength(true); + } + + public void IncreaseLength(bool updateSym) + { + float prevLength = currentLength; + currentLength = Mathf.Min(currentLength + lengthInterval, maxLength); + + UpdateModelState(); + + MoveEndStackNode(currentLength - prevLength); + + UpdateChildrenLength(currentLength - prevLength); + + if (!updateSym) return; + List.Enumerator p = part.symmetryCounterparts.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + if (p.Current != part) + { + p.Current.FindModuleImplementing().IncreaseLength(false); + } + } + p.Dispose(); + } + + public void DecreaseLength(bool updateSym) + { + float prevLength = currentLength; + currentLength = Mathf.Max(currentLength - lengthInterval, 0); + + UpdateModelState(); + + MoveEndStackNode(currentLength - prevLength); + + UpdateChildrenLength(currentLength - prevLength); + + if (!updateSym) return; + List.Enumerator p = part.symmetryCounterparts.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + if (p.Current != part) + { + p.Current.FindModuleImplementing().DecreaseLength(false); + } + } + p.Dispose(); + } + + public void IncreaseRails(bool updateSym) + { + railCountIndex = Mathf.Min(railCountIndex + 1, railCounts.Length - 1); + numberOfRails = railCounts[Mathf.RoundToInt(railCountIndex)]; + UpdateRails(Mathf.RoundToInt(numberOfRails)); + + if (!updateSym) return; + List.Enumerator p = part.symmetryCounterparts.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + p.Current.FindModuleImplementing().SetRailCount(Mathf.RoundToInt(numberOfRails), railCountIndex); + } + } + + public void SetRailCount(int railCount, float railCountIndex) + { + this.railCountIndex = railCountIndex; + numberOfRails = railCount; + UpdateRails(Mathf.RoundToInt(numberOfRails)); + } + + public void DecreaseRails(bool updateSym) + { + railCountIndex = Mathf.Max(railCountIndex - 1, 0); + numberOfRails = railCounts[Mathf.RoundToInt(railCountIndex)]; + UpdateRails(Mathf.RoundToInt(numberOfRails)); + + if (!updateSym) return; + List.Enumerator p = part.symmetryCounterparts.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + p.Current.FindModuleImplementing().SetRailCount(Mathf.RoundToInt(numberOfRails), railCountIndex); + } + } + + public void MoveEndStackNode(float offset) + { + List.Enumerator node = part.attachNodes.GetEnumerator(); + while (node.MoveNext()) + { + if (node.Current == null) continue; + if (node.Current.nodeType == AttachNode.NodeType.Stack && node.Current.id.ToLower().Contains("move")) + { + node.Current.position += offset * Vector3.up; + } + } + node.Dispose(); + } + + IEnumerator DelayedMoveStackNode(float offset) + { + yield return null; + MoveEndStackNode(offset); + } + + void UpdateRails(int railAmount) + { + if (rails.Count == 0) + { + rails.Add(part.FindModelTransform("railTransform")); + IEnumerator t = part.FindModelTransforms("newRail").AsEnumerable().GetEnumerator(); + while (t.MoveNext()) + { + if (t.Current == null) continue; + rails.Add(t.Current); + } + t.Dispose(); + } + + for (int i = 1; i < rails.Count; i++) + { + IEnumerator t = rails[i].GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (t.MoveNext()) + { + if (t.Current == null) continue; + t.Current.name = "deleted"; + } + t.Dispose(); + Destroy(rails[i].gameObject); + } + + rails.RemoveRange(1, rails.Count - 1); + lengthTransforms.Clear(); + heightTransforms.Clear(); + rotationTransforms.Clear(); + + railAngle = 360f / (float)railAmount; + + for (int i = 1; i < railAmount; i++) + { + GameObject newRail = (GameObject)Instantiate(rails[0].gameObject); + newRail.name = "newRail"; + newRail.transform.parent = rails[0].parent; + newRail.transform.localPosition = rails[0].localPosition; + newRail.transform.localRotation = + Quaternion.AngleAxis((float)i * railAngle, + rails[0].parent.InverseTransformDirection(part.transform.up)) * rails[0].localRotation; + rails.Add(newRail.transform); + } + + IEnumerator mt = part.FindModelTransform("rotaryBombBay").GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (mt.MoveNext()) + { + if (mt.Current == null) continue; + switch (mt.Current.name) + { + case "lengthTransform": + lengthTransforms.Add(mt.Current); + break; + + case "heightTransform": + heightTransforms.Add(mt.Current); + break; + + case "rotationTransform": + rotationTransforms.Add(mt.Current); + break; + } + } + mt.Dispose(); + } + + public override void OnStart(StartState state) + { + missileToRailIndex = new Dictionary(); + railToMissileIndex = new Dictionary(); + + lengthInterval = maxLength / intervals; + heightInterval = maxHeight / intervals; + + numberOfRails = railCounts[Mathf.RoundToInt(railCountIndex)]; + + rails = new List(); + rotationTransforms = new List(); + heightTransforms = new List(); + lengthTransforms = new List(); + + UpdateModelState(); + + //MoveEndStackNode(currentLength); + if (HighLogic.LoadedSceneIsEditor) + { + StartCoroutine(DelayedMoveStackNode(currentLength)); + part.OnEditorAttach += OnAttach; + } + + if (!HighLogic.LoadedSceneIsFlight) return; + UpdateMissileChildren(); + RotateToIndex(railIndex, true); + } + + void OnAttach() + { + UpdateRails(Mathf.RoundToInt(numberOfRails)); + } + + void UpdateChildrenHeight(float offset) + { + List.Enumerator p = part.children.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + Vector3 direction = p.Current.transform.position - part.transform.position; + direction = Vector3.ProjectOnPlane(direction, part.transform.up).normalized; + + p.Current.transform.position += direction * offset; + } + p.Dispose(); + } + + void UpdateChildrenLength(float offset) + { + bool parentInFront = + Vector3.Dot(part.parent.transform.position - part.transform.position, part.transform.up) > 0; + if (parentInFront) + { + offset = -offset; + } + + Vector3 direction = part.transform.up; + + if (!parentInFront) + { + List.Enumerator p = part.children.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + if (p.Current.FindModuleImplementing() && p.Current.parent == part) continue; + + p.Current.transform.position += direction * offset; + } + p.Dispose(); + } + + if (parentInFront) + { + part.transform.position += direction * offset; + } + } + + void UpdateModelState() + { + UpdateRails(Mathf.RoundToInt(numberOfRails)); + + for (int i = 0; i < heightTransforms.Count; i++) + { + Vector3 lp = heightTransforms[i].localPosition; + heightTransforms[i].localPosition = new Vector3(lp.x, -currentHeight, lp.z); + } + + for (int i = 0; i < lengthTransforms.Count; i++) + { + Vector3 lp = lengthTransforms[i].localPosition; + lengthTransforms[i].localPosition = new Vector3(lp.x, lp.y, currentLength); + } + + // + } + + public void RotateToMissile(MissileLauncher ml) + { + if (missileCount == 0) return; + if (!ml) return; + + if (readyMissile == ml) return; + + //rotate to this missile specifically + for (int i = 0; i < missileChildren.Length; i++) + { + if (missileChildren[i] != ml) continue; + RotateToIndex(missileToRailIndex[i], false); + nextMissile = ml; + return; + } + + //specific missile isnt here, but check if this type exists here + + if (readyMissile && readyMissile.part.name == ml.part.name) return; //current missile is correct type + + //look for missile type + for (int i = 0; i < missileChildren.Length; i++) + { + if (missileChildren[i].GetShortName() != ml.GetShortName()) continue; + RotateToIndex(missileToRailIndex[i], false); + nextMissile = missileChildren[i]; + return; + } + } + + void UpdateIndexDictionary() + { + missileToRailIndex.Clear(); + railToMissileIndex.Clear(); + + for (int i = 0; i < missileCount; i++) + { + float closestSqr = float.MaxValue; + int rIndex = 0; + for (int r = 0; r < numberOfRails; r++) + { + Vector3 railPos = Quaternion.AngleAxis((float)r * railAngle, part.transform.up) * + part.transform.forward; + railPos += part.transform.position; + float sqrDist = (missileChildren[i].transform.position - railPos).sqrMagnitude; + if (sqrDist < closestSqr) + { + rIndex = r; + closestSqr = sqrDist; + } + } + missileToRailIndex.Add(i, rIndex); + railToMissileIndex.Add(rIndex, i); + //Debug.Log("Adding to index dictionary: " + i + " : " + rIndex); + } + } + + void RotateToIndex(int index, bool instant) + { + //Debug.Log("Rotary rail is rotating to index: " + index); + + if (rotationRoutine != null) + { + StopCoroutine(rotationRoutine); + } + + // if(railIndex == index && readyToFire) return; + + if (missileCount > 0) + { + if (railToMissileIndex.ContainsKey(index)) + { + nextMissile = missileChildren[railToMissileIndex[index]]; + } + } + else + { + nextMissile = null; + } + + if (!nextMissile && missileCount > 0) + { + RotateToIndex(Mathf.RoundToInt(Mathf.Repeat(index + 1, numberOfRails)), instant); + return; + } + + rotationRoutine = StartCoroutine(RotateToIndexRoutine(index, instant)); + } + + Coroutine rotationRoutine; + + IEnumerator RotateToIndexRoutine(int index, bool instant) + { + rdyToFire = false; + rdyMissile = null; + railIndex = index; + + yield return new WaitForSeconds(rotationDelay); + + Quaternion targetRot = Quaternion.Euler(0, 0, (float)index * -railAngle); + + if (instant) + { + for (int i = 0; i < rotationTransforms.Count; i++) + { + rotationTransforms[i].localRotation = targetRot; + } + + UpdateMissilePositions(); + } + else + { + while (rotationTransforms[0].localRotation != targetRot) + { + for (int i = 0; i < rotationTransforms.Count; i++) + { + rotationTransforms[i].localRotation = + Quaternion.RotateTowards(rotationTransforms[i].localRotation, targetRot, + rotationSpeed * Time.fixedDeltaTime); + } + + UpdateMissilePositions(); + yield return new WaitForFixedUpdate(); + } + } + + if (nextMissile) + { + rdyMissile = nextMissile; + rdyToFire = true; + nextMissile = null; + + if (weaponManager) + { + if (wm.weaponIndex > 0 && wm.selectedWeapon.GetPart().name == rdyMissile.part.name) + { + wm.selectedWeapon = rdyMissile; + wm.CurrentMissile = rdyMissile; + } + } + } + } + + public void PrepMissileForFire(MissileLauncher ml) + { + if (ml != readyMissile) + { + //Debug.Log("Rotary rail tried prepping a missile for fire, but it is not in firing position"); + return; + } + + int index = IndexOfMissile(ml); + + if (index >= 0) + { + PrepMissileForFire(index); + } + else + { + //Debug.Log("Tried to prep a missile for firing that doesn't exist or is not attached to the turret."); + } + } + + void PrepMissileForFire(int index) + { + //Debug.Log("Prepping missile for rotary rail fire."); + missileChildren[index].part.CoMOffset = comOffsets[missileChildren[index].part]; + + missileTransforms[index].localPosition = Vector3.zero; + missileTransforms[index].localRotation = Quaternion.identity; + missileChildren[index].part.partTransform.position = missileReferenceTransforms[index].position; + missileChildren[index].part.partTransform.rotation = missileReferenceTransforms[index].rotation; + + missileChildren[index].decoupleForward = false; + + missileChildren[index].part.rb.velocity = + part.rb.GetPointVelocity(missileReferenceTransforms[index].position); + + missileChildren[index].rotaryRail = this; + } + + public void FireMissile(int missileIndex) + { + int nextRailIndex = 0; + + if (!readyToFire) + { + return; + } + + if (missileIndex >= missileChildren.Length) + { + return; + } + + if (missileIndex < missileCount && missileChildren != null && missileChildren[missileIndex] != null) + { + if (missileChildren[missileIndex] != readyMissile) return; + + PrepMissileForFire(missileIndex); + + if (weaponManager) + { + wm.SendTargetDataToMissile(missileChildren[missileIndex]); + } + + string firedMissileName = missileChildren[missileIndex].part.name; + + missileChildren[missileIndex].FireMissile(); + + rdyMissile = null; + rdyToFire = false; + //StartCoroutine(MissileRailRoutine(missileChildren[missileIndex])); + + nextRailIndex = Mathf.RoundToInt(Mathf.Repeat(missileToRailIndex[missileIndex] + 1, numberOfRails)); + + UpdateMissileChildren(); + + if (wm) + { + wm.UpdateList(); + } + + if (railToMissileIndex.ContainsKey(nextRailIndex) && railToMissileIndex[nextRailIndex] < missileCount && + missileChildren[railToMissileIndex[nextRailIndex]].part.name == firedMissileName) + { + RotateToIndex(nextRailIndex, false); + } + } + + //StartCoroutine(RotateToIndexAtEndOfFrame(nextRailIndex, false)); + } + + IEnumerator RotateToIndexAtEndOfFrame(int index, bool instant) + { + yield return new WaitForEndOfFrame(); + RotateToIndex(index, instant); + } + + public void FireMissile(MissileLauncher ml) + { + if (!readyToFire || ml != readyMissile) + { + return; + } + + int index = IndexOfMissile(ml); + if (index >= 0) + { + //Debug.Log("Firing missile index: " + index); + FireMissile(index); + } + else + { + //Debug.Log("Tried to fire a missile that doesn't exist or is not attached to the rail."); + } + } + + private int IndexOfMissile(MissileLauncher ml) + { + if (missileCount == 0) return -1; + + for (int i = 0; i < missileCount; i++) + { + if (missileChildren[i] && missileChildren[i] == ml) + { + return i; + } + } + + return -1; + } + + public void UpdateMissileChildren() + { + missileCount = 0; + + //setup com dictionary + if (comOffsets == null) + { + comOffsets = new Dictionary(); + } + + //destroy the existing reference transform objects + if (missileReferenceTransforms != null) + { + for (int i = 0; i < missileReferenceTransforms.Length; i++) + { + if (missileReferenceTransforms[i]) + { + Destroy(missileReferenceTransforms[i].gameObject); + } + } + } + + List msl = new List(); + List mtfl = new List(); + List mrl = new List(); + List.Enumerator child = part.children.GetEnumerator(); + while (child.MoveNext()) + { + if (child.Current == null) continue; + if (child.Current.parent != part) continue; + + MissileLauncher ml = child.Current.FindModuleImplementing(); + + if (!ml) continue; + + Transform mTf = child.Current.FindModelTransform("missileTransform"); + //fix incorrect hierarchy + if (!mTf) + { + Transform modelTransform = ml.part.partTransform.Find("model"); + + mTf = new GameObject("missileTransform").transform; + Transform[] tfchildren = new Transform[modelTransform.childCount]; + for (int i = 0; i < modelTransform.childCount; i++) + { + tfchildren[i] = modelTransform.GetChild(i); + } + mTf.parent = modelTransform; + mTf.localPosition = Vector3.zero; + mTf.localRotation = Quaternion.identity; + mTf.localScale = Vector3.one; + IEnumerator t = tfchildren.AsEnumerable().GetEnumerator(); + while (t.MoveNext()) + { + if (t.Current == null) continue; + //Debug.Log("MissileTurret moving transform: " + tfchildren[i].gameObject.name); + t.Current.parent = mTf; + } + t.Dispose(); + } + + if (!mTf) continue; + msl.Add(ml); + mtfl.Add(mTf); + Transform mRef = new GameObject().transform; + mRef.position = mTf.position; + mRef.rotation = mTf.rotation; + mRef.parent = rotationTransforms[0]; + mrl.Add(mRef); + + ml.MissileReferenceTransform = mTf; + ml.rotaryRail = this; + + ml.decoupleForward = false; + //ml.decoupleSpeed = Mathf.Max(ml.decoupleSpeed, 4); //removing clamp as some weapons want greater decouple speeds + ml.dropTime = Mathf.Max(ml.dropTime, 0.2f); + + if (!comOffsets.ContainsKey(ml.part)) + { + comOffsets.Add(ml.part, ml.part.CoMOffset); + } + } + child.Dispose(); + + missileChildren = msl.ToArray(); + missileCount = missileChildren.Length; + missileTransforms = mtfl.ToArray(); + missileReferenceTransforms = mrl.ToArray(); + + UpdateIndexDictionary(); + } + + void UpdateMissilePositions() + { + if (missileCount == 0) + { + return; + } + + for (int i = 0; i < missileChildren.Length; i++) + { + if (!missileTransforms[i] || !missileChildren[i] || missileChildren[i].HasFired) continue; + missileTransforms[i].position = missileReferenceTransforms[i].position; + missileTransforms[i].rotation = missileReferenceTransforms[i].rotation; + + Part missilePart = missileChildren[i].part; + Vector3 newCoMOffset = + missilePart.transform.InverseTransformPoint( + missileTransforms[i].TransformPoint(comOffsets[missilePart])); + missilePart.CoMOffset = newCoMOffset; + } + } + } +} diff --git a/BahaTurret/CFEnable.cs b/BDArmory/Modules/CFEnable.cs similarity index 54% rename from BahaTurret/CFEnable.cs rename to BDArmory/Modules/CFEnable.cs index 007672bd3..1ec7bbf37 100644 --- a/BahaTurret/CFEnable.cs +++ b/BDArmory/Modules/CFEnable.cs @@ -1,13 +1,7 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using KSP; - - //Class by NathanKell //http://forum.kerbalspaceprogram.com/threads/76499-0-23-5-CrossFeedEnabler-v1-4-13-14 -namespace BahaTurret +namespace BDArmory.Modules { public class CFEnable : PartModule { @@ -17,21 +11,21 @@ public override void OnLoad(ConfigNode node) base.OnLoad(node); if (part.parent != null && part.parent.fuelLookupTargets != null) { - if (!part.parent.fuelLookupTargets.Contains(this.part)) - part.parent.fuelLookupTargets.Add(this.part); - if (!this.part.fuelLookupTargets.Contains(part.parent)) + if (!part.parent.fuelLookupTargets.Contains(part)) + part.parent.fuelLookupTargets.Add(part); + if (!part.fuelLookupTargets.Contains(part.parent)) part.fuelLookupTargets.Add(part.parent); - } + } } - public override void OnStart(PartModule.StartState state) + public override void OnStart(StartState state) { base.OnStart(state); if (part.parent != null && part.parent.fuelLookupTargets != null) { - if (!part.parent.fuelLookupTargets.Contains(this.part)) - part.parent.fuelLookupTargets.Add(this.part); - if (!this.part.fuelLookupTargets.Contains(part.parent)) + if (!part.parent.fuelLookupTargets.Contains(part)) + part.parent.fuelLookupTargets.Add(part); + if (!part.fuelLookupTargets.Contains(part.parent)) part.fuelLookupTargets.Add(part.parent); } } @@ -41,9 +35,9 @@ public override void OnInitialize() base.OnInitialize(); if (part.parent != null && part.parent.fuelLookupTargets != null) { - if (!part.parent.fuelLookupTargets.Contains(this.part)) - part.parent.fuelLookupTargets.Add(this.part); - if (!this.part.fuelLookupTargets.Contains(part.parent)) + if (!part.parent.fuelLookupTargets.Contains(part)) + part.parent.fuelLookupTargets.Add(part); + if (!part.fuelLookupTargets.Contains(part.parent)) part.fuelLookupTargets.Add(part.parent); } } @@ -52,9 +46,9 @@ public void OnDestroy() { if (part.parent != null && part.parent.fuelLookupTargets != null) { - if (part.parent.fuelLookupTargets.Contains(this.part)) - part.parent.fuelLookupTargets.Remove(this.part); + if (part.parent.fuelLookupTargets.Contains(part)) + part.parent.fuelLookupTargets.Remove(part); } } } -} \ No newline at end of file +} diff --git a/BDArmory/Modules/ClusterBomb.cs b/BDArmory/Modules/ClusterBomb.cs new file mode 100644 index 000000000..bfc8b3712 --- /dev/null +++ b/BDArmory/Modules/ClusterBomb.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using BDArmory.Core.Extension; +using BDArmory.FX; +using BDArmory.Misc; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class ClusterBomb : PartModule + { + List submunitions; + List fairings; + MissileLauncher missileLauncher; + + bool deployed; + + [KSPField(isPersistant = false)] + public string subExplModelPath = "BDArmory/Models/explosion/explosion"; + + [KSPField(isPersistant = false)] + public string subExplSoundPath = "BDArmory/Sounds/subExplode"; + + [KSPField(isPersistant = false)] + public float deployDelay = 2.5f; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DeployAltitude"),//Deploy Altitude + UI_FloatRange(minValue = 100f, maxValue = 1000f, stepIncrement = 10f, scene = UI_Scene.Editor)] + public float deployAltitude = 400; + + [KSPField(isPersistant = false)] + public float submunitionMaxSpeed = 10; + + [KSPField(isPersistant = false)] + public bool swapCollidersOnDeploy = true; + + public override void OnStart(StartState state) + { + submunitions = new List(); + IEnumerator sub = part.FindModelTransforms("submunition").AsEnumerable().GetEnumerator(); + + while (sub.MoveNext()) + { + if (sub.Current == null) continue; + submunitions.Add(sub.Current.gameObject); + + if (HighLogic.LoadedSceneIsFlight) + { + Rigidbody subRb = sub.Current.gameObject.GetComponent(); + if (!subRb) + { + subRb = sub.Current.gameObject.AddComponent(); + } + + subRb.isKinematic = true; + subRb.mass = part.mass / part.FindModelTransforms("submunition").Length; + } + sub.Current.gameObject.SetActive(false); + } + sub.Dispose(); + + fairings = new List(); + IEnumerator fairing = part.FindModelTransforms("fairing").AsEnumerable().GetEnumerator(); + while (fairing.MoveNext()) + { + if (fairing.Current == null) continue; + fairings.Add(fairing.Current.gameObject); + if (!HighLogic.LoadedSceneIsFlight) continue; + Rigidbody fairingRb = fairing.Current.gameObject.GetComponent(); + if (!fairingRb) + { + fairingRb = fairing.Current.gameObject.AddComponent(); + } + fairingRb.isKinematic = true; + fairingRb.mass = 0.05f; + } + fairing.Dispose(); + + missileLauncher = part.GetComponent(); + } + + public override void OnFixedUpdate() + { + if (missileLauncher != null && missileLauncher.HasFired && + missileLauncher.TimeIndex > deployDelay && + !deployed && AltitudeTrigger()) + { + DeploySubmunitions(); + } + } + + void DeploySubmunitions() + { + missileLauncher.sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/flare")); + FXMonger.Explode(part, transform.position + part.rb.velocity * Time.fixedDeltaTime, 0.1f); + + deployed = true; + if (swapCollidersOnDeploy) + { + IEnumerator col = part.GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (col.MoveNext()) + { + if (col.Current == null) continue; + col.Current.enabled = !col.Current.enabled; + } + col.Dispose(); + } + + missileLauncher.sfAudioSource.priority = 999; + + List.Enumerator sub = submunitions.GetEnumerator(); + while (sub.MoveNext()) + { + if (sub.Current == null) continue; + sub.Current.SetActive(true); + sub.Current.transform.parent = null; + Vector3 direction = (sub.Current.transform.position - part.transform.position).normalized; + Rigidbody subRB = sub.Current.GetComponent(); + subRB.isKinematic = false; + subRB.velocity = part.rb.velocity + Krakensbane.GetFrameVelocityV3f() + + (UnityEngine.Random.Range(submunitionMaxSpeed / 10, submunitionMaxSpeed) * direction); + + Submunition subScript = sub.Current.AddComponent(); + subScript.enabled = true; + subScript.deployed = true; + subScript.blastForce = missileLauncher.GetTntMass(); + subScript.blastHeat = missileLauncher.blastHeat; + subScript.blastRadius = missileLauncher.GetBlastRadius(); + subScript.subExplModelPath = subExplModelPath; + subScript.subExplSoundPath = subExplSoundPath; + sub.Current.AddComponent(); + } + + List.Enumerator fairing = fairings.GetEnumerator(); + while (fairing.MoveNext()) + { + if (fairing.Current == null) continue; + Vector3 direction = (fairing.Current.transform.position - part.transform.position).normalized; + Rigidbody fRB = fairing.Current.GetComponent(); + fRB.isKinematic = false; + fRB.velocity = part.rb.velocity + Krakensbane.GetFrameVelocityV3f() + ((submunitionMaxSpeed + 2) * direction); + fairing.Current.AddComponent(); + fairing.Current.GetComponent().drag = 0.2f; + ClusterBombFairing fairingScript = fairing.Current.AddComponent(); + fairingScript.deployed = true; + } + + fairing.Dispose(); + + part.explosionPotential = 0; + missileLauncher.HasFired = false; + + part.Destroy(); + } + + bool AltitudeTrigger() + { + double asl = vessel.mainBody.GetAltitude(vessel.CoM); + double radarAlt = asl - vessel.terrainAltitude; + + return (radarAlt < deployAltitude || asl < deployAltitude) && vessel.verticalSpeed < 0; + } + } + + public class Submunition : MonoBehaviour + { + public bool deployed; + public float blastRadius; + public float blastForce; + public float blastHeat; + public string subExplModelPath; + public string subExplSoundPath; + Vector3 currPosition; + Vector3 prevPosition; + + float startTime; + + Rigidbody rb; + + void Start() + { + startTime = Time.time; + currPosition = transform.position; + prevPosition = transform.position; + rb = GetComponent(); + } + + void OnCollisionEnter(Collision col) + { + ContactPoint contact = col.contacts[0]; + Vector3 pos = contact.point; + ExplosionFx.CreateExplosion(pos, blastForce, subExplModelPath, subExplSoundPath, true); + } + + void FixedUpdate() + { + if (deployed) + { + if (Time.time - startTime > 30) + { + Destroy(gameObject); + return; + } + + //floating origin and velocity offloading corrections + if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) + { + transform.position -= FloatingOrigin.OffsetNonKrakensbane; + prevPosition -= FloatingOrigin.OffsetNonKrakensbane; + } + + currPosition = transform.position; + float dist = (currPosition - prevPosition).magnitude; + Ray ray = new Ray(prevPosition, currPosition - prevPosition); + RaycastHit hit; + + if (Physics.Raycast(ray, out hit, dist, 9076737)) + { + Part hitPart = null; + try + { + hitPart = hit.collider.gameObject.GetComponentInParent(); + } + catch (NullReferenceException) + { + Debug.Log("[BDArmory]:NullReferenceException for Submunition Hit"); + return; + } + + if (hitPart != null || CheckBuildingHit(hit)) + { + Detonate(hit.point); + } + else if (hitPart == null) + { + Detonate(currPosition); + } + } + else if (FlightGlobals.getAltitudeAtPos(currPosition) <= 0) + { + Detonate(currPosition); + } + + prevPosition = transform.position; + } + } + + void Detonate(Vector3 pos) + { + ExplosionFx.CreateExplosion(pos, blastForce, subExplModelPath, subExplSoundPath, true); + Destroy(gameObject); + } + + private bool CheckBuildingHit(RaycastHit hit) + { + DestructibleBuilding building = null; + try + { + building = hit.collider.gameObject.GetComponentUpwards(); + } + catch (Exception) { } + + if (building != null && building.IsIntact) + { + return true; + } + return false; + } + } + + public class ClusterBombFairing : MonoBehaviour + { + public bool deployed; + + Vector3 currPosition; + Vector3 prevPosition; + float startTime; + + Rigidbody rb; + + void Start() + { + startTime = Time.time; + currPosition = transform.position; + prevPosition = transform.position; + rb = GetComponent(); + } + + void FixedUpdate() + { + if (deployed) + { + //floating origin and velocity offloading corrections + if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) + { + transform.position -= FloatingOrigin.OffsetNonKrakensbane; + prevPosition -= FloatingOrigin.OffsetNonKrakensbane; + } + + currPosition = transform.position; + float dist = (currPosition - prevPosition).magnitude; + Ray ray = new Ray(prevPosition, currPosition - prevPosition); + RaycastHit hit; + if (Physics.Raycast(ray, out hit, dist, 9076737)) + { + Destroy(gameObject); + } + else if (FlightGlobals.getAltitudeAtPos(currPosition) <= 0) + { + Destroy(gameObject); + } + else if (Time.time - startTime > 20) + { + Destroy(gameObject); + } + } + } + } +} diff --git a/BDArmory/Modules/EngageableWeapon.cs b/BDArmory/Modules/EngageableWeapon.cs new file mode 100644 index 000000000..d9e8ab8ad --- /dev/null +++ b/BDArmory/Modules/EngageableWeapon.cs @@ -0,0 +1,132 @@ +using KSP.Localization; +namespace BDArmory.Modules +{ + public abstract class EngageableWeapon : PartModule, IEngageService + { + [KSPField(isPersistant = true)] + public bool engageEnabled = true; + + // Weapon usage settings + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_EngageRangeMin"),//Engage Range Min + UI_FloatRange(minValue = 0f, maxValue = 5000f, stepIncrement = 100f, scene = UI_Scene.Editor)] + public float engageRangeMin; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_EngageRangeMax"),//Engage Range Max + UI_FloatRange(minValue = 0f, maxValue = 5000f, stepIncrement = 100f, scene = UI_Scene.Editor)] + public float engageRangeMax; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_EngageAir"),//Engage Air + UI_Toggle(disabledText = "#LOC_BDArmory_false", enabledText = "#LOC_BDArmory_true")]//false--true + public bool engageAir = true; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_EngageMissile"),//Engage Missile + UI_Toggle(disabledText = "#LOC_BDArmory_false", enabledText = "#LOC_BDArmory_true")]//false--true + public bool engageMissile = true; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_EngageSurface"),//Engage Surface + UI_Toggle(disabledText = "#LOC_BDArmory_false", enabledText = "#LOC_BDArmory_true")]//false--true + public bool engageGround = true; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_EngageSLW"),//Engage SLW + UI_Toggle(disabledText = "#LOC_BDArmory_false", enabledText = "#LOC_BDArmory_true")]//false--true + public bool engageSLW = true; + + [KSPEvent(guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_DisableEngageOptions", active = true)]//Disable Engage Options + public void ToggleEngageOptions() + { + engageEnabled = !engageEnabled; + + if (engageEnabled == false) + { + Events["ToggleEngageOptions"].guiName = Localizer.Format("#LOC_BDArmory_EnableEngageOptions");//"Enable Engage Options" + } + else + { + Events["ToggleEngageOptions"].guiName = Localizer.Format("#LOC_BDArmory_DisableEngageOptions");//"Disable Engage Options" + } + + Fields["engageRangeMin"].guiActive = engageEnabled; + Fields["engageRangeMin"].guiActiveEditor = engageEnabled; + Fields["engageRangeMax"].guiActive = engageEnabled; + Fields["engageRangeMax"].guiActiveEditor = engageEnabled; + Fields["engageAir"].guiActive = engageEnabled; + Fields["engageAir"].guiActiveEditor = engageEnabled; + Fields["engageMissile"].guiActive = engageEnabled; + Fields["engageMissile"].guiActiveEditor = engageEnabled; + Fields["engageGround"].guiActive = engageEnabled; + Fields["engageGround"].guiActiveEditor = engageEnabled; + Fields["engageSLW"].guiActive = engageEnabled; + Fields["engageSLW"].guiActiveEditor = engageEnabled; + + Misc.Misc.RefreshAssociatedWindows(part); + } + + public void OnRangeUpdated(BaseField field, object obj) + { + // ensure max >= min + if (engageRangeMax < engageRangeMin) + engageRangeMax = engageRangeMin; + } + + protected void InitializeEngagementRange(float min, float max) + { + UI_FloatRange rangeMin = (UI_FloatRange)Fields["engageRangeMin"].uiControlEditor; + rangeMin.minValue = min; + rangeMin.maxValue = max; + rangeMin.stepIncrement = (max - min) / 100f; + rangeMin.onFieldChanged = OnRangeUpdated; + + UI_FloatRange rangeMax = (UI_FloatRange)Fields["engageRangeMax"].uiControlEditor; + rangeMax.minValue = min; + rangeMax.maxValue = max; + rangeMax.stepIncrement = (max - min) / 100f; + rangeMax.onFieldChanged = OnRangeUpdated; + + if ((engageRangeMin == 0) && (engageRangeMax == 0)) + { + // no sensible settings yet, set to default + engageRangeMin = min; + engageRangeMax = max; + } + } + + //implementations from Interface + public float GetEngagementRangeMin() + { + return engageRangeMin; + } + + public float GetEngagementRangeMax() + { + return engageRangeMax; + } + + public bool GetEngageAirTargets() + { + return engageAir; + } + + public bool GetEngageMissileTargets() + { + return engageMissile; + } + + public bool GetEngageGroundTargets() + { + return engageGround; + } + + public bool GetEngageSLWTargets() + { + return engageSLW; + } + + [KSPField(isPersistant = true)] + public string shortName = string.Empty; + + public string GetShortName() + { + return shortName; + } + } +} diff --git a/BDArmory/Modules/IEngageService.cs b/BDArmory/Modules/IEngageService.cs new file mode 100644 index 000000000..e8936c0f8 --- /dev/null +++ b/BDArmory/Modules/IEngageService.cs @@ -0,0 +1,15 @@ +namespace BDArmory.Modules +{ + public interface IEngageService + { + float GetEngagementRangeMax(); + + bool GetEngageAirTargets(); + + bool GetEngageMissileTargets(); + + bool GetEngageGroundTargets(); + + bool GetEngageSLWTargets(); + } +} diff --git a/BDArmory/Modules/MissileBase.cs b/BDArmory/Modules/MissileBase.cs new file mode 100644 index 000000000..0160d4098 --- /dev/null +++ b/BDArmory/Modules/MissileBase.cs @@ -0,0 +1,1079 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.CounterMeasure; +using BDArmory.FX; +using BDArmory.Guidances; +using BDArmory.Misc; +using BDArmory.Radar; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Modules +{ + public abstract class MissileBase : EngageableWeapon, IBDWeapon + { + // High Speed missile fix + /// ////////////////////////////////// + [KSPField(isPersistant = true)] + public float DetonationOffset = 0.1f; + + [KSPField(isPersistant = true)] + public bool autoDetCalc = false; + /// ////////////////////////////////// + + protected WeaponClasses weaponClass; + + public WeaponClasses GetWeaponClass() + { + return weaponClass; + } + + public string GetMissileType() + { + return missileType; + } + + [KSPField] + public string missileType = "missile"; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxStaticLaunchRange"), UI_FloatRange(minValue = 5000f, maxValue = 50000f, stepIncrement = 1000f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Max Static Launch Range + public float maxStaticLaunchRange = 5000; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MinStaticLaunchRange"), UI_FloatRange(minValue = 10f, maxValue = 4000f, stepIncrement = 100f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Min Static Launch Range + public float minStaticLaunchRange = 10; + + [KSPField] + public float minLaunchSpeed = 0; + + public virtual float ClearanceRadius => 0.14f; + + public virtual float ClearanceLength => 0.14f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxOffBoresight"),//Max Off Boresight + UI_FloatRange(minValue = 0f, maxValue = 360f, stepIncrement = 5f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)] + public float maxOffBoresight = 360; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_DetonationDistanceOverride"), UI_FloatRange(minValue = 0f, maxValue = 100f, stepIncrement = 1f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Detonation distance override + public float DetonationDistance = -1; + + //[KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "SLW Offset"), UI_FloatRange(minValue = -1000f, maxValue = 0f, stepIncrement = 100f, affectSymCounterparts = UI_Scene.All)] + public float SLWOffset = 0; + + public float getSWLWOffset + { + get + { + return SLWOffset; + } + } + + [KSPField] + public bool guidanceActive = true; + + [KSPField] + public float lockedSensorFOV = 2.5f; + + [KSPField] + public float heatThreshold = 150; + + [KSPField] + public bool allAspect = false; + + [KSPField] + public bool isTimed = false; + + [KSPField] + public bool radarLOAL = false; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DropTime"),//Drop Time + UI_FloatRange(minValue = 0f, maxValue = 5f, stepIncrement = 0.5f, scene = UI_Scene.Editor)] + public float dropTime = 0.5f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_InCargoBay"),//In Cargo Bay: + UI_Toggle(disabledText = "#LOC_BDArmory_false", enabledText = "#LOC_BDArmory_true", affectSymCounterparts = UI_Scene.All)]//False--True + public bool inCargoBay = false; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_DetonationTime"),//Detonation Time + UI_FloatRange(minValue = 2f, maxValue = 30f, stepIncrement = 0.5f, scene = UI_Scene.Editor)] + public float detonationTime = 2; + + [KSPField] + public float activeRadarRange = 6000; + + [Obsolete("Use activeRadarLockTrackCurve!")] + [KSPField] + public float activeRadarMinThresh = 140; + + [KSPField] + public FloatCurve activeRadarLockTrackCurve = new FloatCurve(); // floatcurve to define min/max range and lockable radar cross section + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_BallisticOvershootFactor"),//Ballistic Overshoot factor + UI_FloatRange(minValue = 0.5f, maxValue = 1.5f, stepIncrement = 0.01f, scene = UI_Scene.Editor)] + public float BallisticOverShootFactor = 0.7f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_BallisticAnglePath"),//Ballistic Angle path + UI_FloatRange(minValue = 5f, maxValue = 60f, stepIncrement = 5f, scene = UI_Scene.Editor)] + public float BallisticAngle = 45.0f; + + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_CruiseAltitude"), UI_FloatRange(minValue = 1f, maxValue = 500f, stepIncrement = 10f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Cruise Altitude + public float CruiseAltitude = 500; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_CruiseSpeed"), UI_FloatRange(minValue = 100f, maxValue = 6000f, stepIncrement = 50f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Cruise speed + public float CruiseSpeed = 300; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_CruisePredictionTime"), UI_FloatRange(minValue = 1f, maxValue = 15f, stepIncrement = 1f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Cruise prediction time + public float CruisePredictionTime = 5; + + [KSPField] + public float missileRadarCrossSection = RadarUtils.RCS_MISSILES; // radar cross section of this missile for detection purposes + + public enum MissileStates { Idle, Drop, Boost, Cruise, PostThrust } + + public enum DetonationDistanceStates { NotSafe, Cruising, CheckingProximity, Detonate } + + public enum TargetingModes { None, Radar, Heat, Laser, Gps, AntiRad } + + public MissileStates MissileState { get; set; } = MissileStates.Idle; + + public DetonationDistanceStates DetonationDistanceState { get; set; } = DetonationDistanceStates.NotSafe; + + public enum GuidanceModes { None, AAMLead, AAMPure, AGM, AGMBallistic, Cruise, STS, Bomb, RCS, BeamRiding, SLW } + + public GuidanceModes GuidanceMode; + + public bool HasFired { get; set; } = false; + + public BDTeam Team { get; set; } + + public bool HasMissed { get; set; } = false; + + public Vector3 TargetPosition { get; set; } = Vector3.zero; + + public Vector3 TargetVelocity { get; set; } = Vector3.zero; + + public Vector3 TargetAcceleration { get; set; } = Vector3.zero; + + public float TimeIndex => Time.time - TimeFired; + + public TargetingModes TargetingMode { get; set; } + + public TargetingModes TargetingModeTerminal { get; set; } + + public float TimeToImpact { get; set; } + + public bool TargetAcquired { get; set; } + + public bool ActiveRadar { get; set; } + + public Vessel SourceVessel { get; set; } = null; + + public bool HasExploded { get; set; } = false; + + protected IGuidance _guidance; + + private double _lastVerticalSpeed; + private double _lastHorizontalSpeed; + + public double HorizontalAcceleration + { + get + { + var result = (vessel.horizontalSrfSpeed - _lastHorizontalSpeed); + _lastHorizontalSpeed = vessel.horizontalSrfSpeed; + return result; + + } + } + + public double VerticalAcceleration + { + get + { + var result = (vessel.horizontalSrfSpeed - _lastHorizontalSpeed); + _lastVerticalSpeed = vessel.verticalSpeed; + return result; + } + } + + + + public float Throttle + { + get + { + return _throttle; + } + + set + { + _throttle = Mathf.Clamp01(value); + } + } + + public float TimeFired = -1; + + protected float lockFailTimer = -1; + + public Vessel legacyTargetVessel; + + public Transform MissileReferenceTransform; + + protected ModuleTargetingCamera targetingPod; + + //laser stuff + public ModuleTargetingCamera lockedCamera; + protected Vector3 lastLaserPoint; + protected Vector3 laserStartPosition; + protected Vector3 startDirection; + + //GPS stuff + public Vector3d targetGPSCoords; + + //heat stuff + public TargetSignatureData heatTarget; + + //radar stuff + public VesselRadarData vrd; + public TargetSignatureData radarTarget; + private TargetSignatureData[] scannedTargets; + public MissileFire TargetMf = null; + private LineRenderer LR; + + private int snapshotTicker; + private int locksCount = 0; + private float _radarFailTimer = 0; + private float maxRadarFailTime = 5; + private float lastRWRPing = 0; + private bool radarLOALSearching = false; + protected bool checkMiss = false; + public StringBuilder debugString = new StringBuilder(); + + private float _throttle = 1f; + Vector3 previousPos; + + public string Sublabel; + public int missilecount = 0; //#191 + + public void GetMissileCount() // could stick this in GetSublabel, but that gets called every frame by BDArmorySetup? + { + missilecount = 0; + List.Enumerator craftPart = vessel.parts.GetEnumerator(); + while (craftPart.MoveNext()) + { + if (craftPart.Current == null) continue; + if (part == null) continue; + if (part.name == null) continue; + if (craftPart.Current.name != part.name) continue; + missilecount++; + } + craftPart.Dispose(); + } + + public string GetSubLabel() + { + return Sublabel = "Guidance: " + Enum.GetName(typeof(TargetingModes), TargetingMode) + "; Remaining: "+ missilecount; // + } + + public Part GetPart() + { + return part; + } + + public abstract void FireMissile(); + + public abstract void Jettison(); + + public abstract float GetBlastRadius(); + + protected abstract void PartDie(Part p); + + protected void DisablingExplosives(Part p) + { + if (p == null) return; + + var explosive = p.FindModuleImplementing(); + if (explosive != null) + { + p.FindModuleImplementing().Armed = false; + } + } + + protected void SetupExplosive(Part p) + { + if (p == null) return; + + var explosive = p.FindModuleImplementing(); + if (explosive != null) + { + p.FindModuleImplementing().Armed = true; + if (GuidanceMode == GuidanceModes.AGM || GuidanceMode == GuidanceModes.AGMBallistic) + { + p.FindModuleImplementing().Shaped = true; + } + } + } + + public abstract void Detonate(); + + public abstract Vector3 GetForwardTransform(); + + protected void AddTargetInfoToVessel() + { + TargetInfo info = vessel.gameObject.AddComponent(); + info.Team = Team; + info.isMissile = true; + info.MissileBaseModule = this; + } + + [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_GPSTarget", active = true, name = "GPSTarget")]//GPS Target + public void assignGPSTarget() + { + if (HighLogic.LoadedSceneIsFlight) + PickGPSTarget(); + } + + [KSPField(isPersistant = true)] + public bool gpsSet = false; + + [KSPField(isPersistant = true)] + public Vector3 assignedGPSCoords; + + [KSPField(isPersistant = true, guiName = "#LOC_BDArmory_GPSTarget")]//GPS Target + public string gpsTargetName = ""; + + + + void PickGPSTarget() + { + gpsSet = true; + Fields["gpsTargetName"].guiActive = true; + gpsTargetName = BDArmorySetup.Instance.ActiveWeaponManager.designatedGPSInfo.name; + assignedGPSCoords = BDArmorySetup.Instance.ActiveWeaponManager.designatedGPSCoords; + } + + public Vector3d UpdateGPSTarget() + { + Vector3 gpsTargetCoords_; + + if (gpsSet && assignedGPSCoords != null) + { + gpsTargetCoords_ = assignedGPSCoords; + } + else + { + gpsTargetCoords_ = targetGPSCoords; + } + + if (TargetAcquired) + { + TargetPosition = VectorUtils.GetWorldSurfacePostion(gpsTargetCoords_, vessel.mainBody); + TargetVelocity = Vector3.zero; + TargetAcceleration = Vector3.zero; + } + else + { + guidanceActive = false; + } + + return gpsTargetCoords_; + } + + protected void UpdateHeatTarget() + { + if (lockFailTimer > 1) + { + legacyTargetVessel = null; + TargetAcquired = false; + return; + } + + + if (heatTarget.exists && lockFailTimer < 0) + { + lockFailTimer = 0; + } + if (lockFailTimer >= 0) + { + Ray lookRay = new Ray(transform.position, heatTarget.position + (heatTarget.velocity * Time.fixedDeltaTime) - transform.position); + heatTarget = BDATargetManager.GetHeatTarget(SourceVessel, vessel, lookRay, lockedSensorFOV / 2, heatThreshold, allAspect, SourceVessel?.gameObject?.GetComponent()); + + if (heatTarget.exists) + { + TargetAcquired = true; + TargetPosition = heatTarget.position + (2 * heatTarget.velocity * Time.fixedDeltaTime); + TargetVelocity = heatTarget.velocity; + TargetAcceleration = heatTarget.acceleration; + lockFailTimer = 0; + } + else + { + TargetAcquired = false; + if (FlightGlobals.ready) + { + lockFailTimer += Time.fixedDeltaTime; + } + } + } + } + + protected void SetAntiRadTargeting() + { + if (TargetingMode == TargetingModes.AntiRad && TargetAcquired) + { + RadarWarningReceiver.OnRadarPing += ReceiveRadarPing; + } + } + + protected void SetLaserTargeting() + { + if (TargetingMode == TargetingModes.Laser) + { + laserStartPosition = MissileReferenceTransform.position; + if (lockedCamera) + { + TargetAcquired = true; + TargetPosition = lastLaserPoint = lockedCamera.groundTargetPosition; + targetingPod = lockedCamera; + } + } + } + + protected void UpdateLaserTarget() + { + if (TargetAcquired) + { + if (lockedCamera && lockedCamera.groundStabilized && !lockedCamera.gimbalLimitReached && lockedCamera.surfaceDetected) //active laser target + { + TargetPosition = lockedCamera.groundTargetPosition; + TargetVelocity = (TargetPosition - lastLaserPoint) / Time.fixedDeltaTime; + TargetAcceleration = Vector3.zero; + lastLaserPoint = TargetPosition; + + if (GuidanceMode == GuidanceModes.BeamRiding && TimeIndex > 0.25f && Vector3.Dot(GetForwardTransform(), part.transform.position - lockedCamera.transform.position) < 0) + { + TargetAcquired = false; + lockedCamera = null; + } + } + else //lost active laser target, home on last known position + { + if (CMSmoke.RaycastSmoke(new Ray(transform.position, lastLaserPoint - transform.position))) + { + //Debug.Log("Laser missileBase affected by smoke countermeasure"); + float angle = VectorUtils.FullRangePerlinNoise(0.75f * Time.time, 10) * BDArmorySettings.SMOKE_DEFLECTION_FACTOR; + TargetPosition = VectorUtils.RotatePointAround(lastLaserPoint, transform.position, VectorUtils.GetUpDirection(transform.position), angle); + TargetVelocity = Vector3.zero; + TargetAcceleration = Vector3.zero; + lastLaserPoint = TargetPosition; + } + else + { + TargetPosition = lastLaserPoint; + } + } + } + else + { + ModuleTargetingCamera foundCam = null; + bool parentOnly = (GuidanceMode == GuidanceModes.BeamRiding); + foundCam = BDATargetManager.GetLaserTarget(this, parentOnly); + if (foundCam != null && foundCam.cameraEnabled && foundCam.groundStabilized && BDATargetManager.CanSeePosition(foundCam.groundTargetPosition, vessel.transform.position, MissileReferenceTransform.position)) + { + Debug.Log("[BDArmory]: Laser guided missileBase actively found laser point. Enabling guidance."); + lockedCamera = foundCam; + TargetAcquired = true; + } + } + } + + protected void UpdateRadarTarget() + { + TargetAcquired = false; + + float angleToTarget = Vector3.Angle(radarTarget.predictedPosition - transform.position, GetForwardTransform()); + + if (radarTarget.exists) + { + // locked-on before launch, passive radar guidance or waiting till in active radar range: + if (!ActiveRadar && ((radarTarget.predictedPosition - transform.position).sqrMagnitude > Mathf.Pow(activeRadarRange, 2) || angleToTarget > maxOffBoresight * 0.75f)) + { + if (vrd) + { + TargetSignatureData t = TargetSignatureData.noTarget; + List possibleTargets = vrd.GetLockedTargets(); + for (int i = 0; i < possibleTargets.Count; i++) + { + if (possibleTargets[i].vessel == radarTarget.vessel) + { + t = possibleTargets[i]; + } + } + + if (t.exists) + { + TargetAcquired = true; + radarTarget = t; + TargetPosition = radarTarget.predictedPositionWithChaffFactor; + TargetVelocity = radarTarget.velocity; + TargetAcceleration = radarTarget.acceleration; + _radarFailTimer = 0; + return; + } + else + { + if (_radarFailTimer > maxRadarFailTime) + { + Debug.Log("[BDArmory]: Semi-Active Radar guidance failed. Parent radar lost target."); + radarTarget = TargetSignatureData.noTarget; + legacyTargetVessel = null; + return; + } + else + { + if (_radarFailTimer == 0) + { + Debug.Log("[BDArmory]: Semi-Active Radar guidance failed - waiting for data"); + } + _radarFailTimer += Time.fixedDeltaTime; + radarTarget.timeAcquired = Time.time; + radarTarget.position = radarTarget.predictedPosition; + TargetPosition = radarTarget.predictedPositionWithChaffFactor; + TargetVelocity = radarTarget.velocity; + TargetAcceleration = Vector3.zero; + TargetAcquired = true; + } + } + } + else + { + Debug.Log("[BDArmory]: Semi-Active Radar guidance failed. Out of range and no data feed."); + radarTarget = TargetSignatureData.noTarget; + legacyTargetVessel = null; + return; + } + } + else + { + // active radar with target locked: + vrd = null; + + if (angleToTarget > maxOffBoresight) + { + Debug.Log("[BDArmory]: Active Radar guidance failed. Target is out of active seeker gimbal limits."); + radarTarget = TargetSignatureData.noTarget; + legacyTargetVessel = null; + return; + } + else + { + if (scannedTargets == null) scannedTargets = new TargetSignatureData[5]; + TargetSignatureData.ResetTSDArray(ref scannedTargets); + Ray ray = new Ray(transform.position, radarTarget.predictedPosition - transform.position); + bool pingRWR = Time.time - lastRWRPing > 0.4f; + if (pingRWR) lastRWRPing = Time.time; + bool radarSnapshot = (snapshotTicker > 10); + if (radarSnapshot) + { + snapshotTicker = 0; + } + else + { + snapshotTicker++; + } + + //RadarUtils.UpdateRadarLock(ray, lockedSensorFOV, activeRadarMinThresh, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); + RadarUtils.RadarUpdateMissileLock(ray, lockedSensorFOV, ref scannedTargets, 0.4f, this); + + float sqrThresh = radarLOALSearching ? Mathf.Pow(500, 2) : Mathf.Pow(40, 2); + + if (radarLOAL && radarLOALSearching && !radarSnapshot) + { + //only scan on snapshot interval + } + else + { + for (int i = 0; i < scannedTargets.Length; i++) + { + if (scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) + { + //re-check engagement envelope, only lock appropriate targets + if (CheckTargetEngagementEnvelope(scannedTargets[i].targetInfo)) + { + radarTarget = scannedTargets[i]; + TargetAcquired = true; + radarLOALSearching = false; + TargetPosition = radarTarget.predictedPositionWithChaffFactor + (radarTarget.velocity * Time.fixedDeltaTime); + TargetVelocity = radarTarget.velocity; + TargetAcceleration = radarTarget.acceleration; + _radarFailTimer = 0; + if (!ActiveRadar && Time.time - TimeFired > 1) + { + if (locksCount == 0) + { + if (weaponClass == WeaponClasses.SLW) + RadarWarningReceiver.PingRWR(ray, lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.Torpedo, 2f); + else + RadarWarningReceiver.PingRWR(ray, lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); + Debug.Log("[BDArmory]: Pitbull! Radar missilebase has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); + } + else if (locksCount > 2) + { + guidanceActive = false; + checkMiss = true; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Active Radar guidance failed. Radar missileBase reached max re-lock attempts."); + } + } + locksCount++; + } + ActiveRadar = true; + return; + } + } + } + } + + if (radarLOAL) + { + radarLOALSearching = true; + TargetAcquired = true; + TargetPosition = radarTarget.predictedPositionWithChaffFactor + (radarTarget.velocity * Time.fixedDeltaTime); + TargetVelocity = radarTarget.velocity; + TargetAcceleration = Vector3.zero; + ActiveRadar = false; + _radarFailTimer = 0; + } + else + { + Debug.Log("[BDArmory]: Active Radar guidance failed. No target locked."); + radarTarget = TargetSignatureData.noTarget; + legacyTargetVessel = null; + radarLOALSearching = false; + TargetAcquired = false; + ActiveRadar = false; + } + } + } + } + else if (radarLOAL && radarLOALSearching) + { + // not locked on before launch, trying lock-on after launch: + + if (scannedTargets == null) scannedTargets = new TargetSignatureData[5]; + TargetSignatureData.ResetTSDArray(ref scannedTargets); + Ray ray = new Ray(transform.position, GetForwardTransform()); + bool pingRWR = Time.time - lastRWRPing > 0.4f; + if (pingRWR) lastRWRPing = Time.time; + bool radarSnapshot = (snapshotTicker > 5); + if (radarSnapshot) + { + snapshotTicker = 0; + } + else + { + snapshotTicker++; + } + + //RadarUtils.UpdateRadarLock(ray, lockedSensorFOV * 3, activeRadarMinThresh * 2, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); + RadarUtils.RadarUpdateMissileLock(ray, lockedSensorFOV * 3, ref scannedTargets, 0.4f, this); + + float sqrThresh = Mathf.Pow(300, 2); + + float smallestAngle = 360; + TargetSignatureData lockedTarget = TargetSignatureData.noTarget; + + for (int i = 0; i < scannedTargets.Length; i++) + { + if (scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) + { + //re-check engagement envelope, only lock appropriate targets + if (CheckTargetEngagementEnvelope(scannedTargets[i].targetInfo)) + { + float angle = Vector3.Angle(scannedTargets[i].predictedPosition - transform.position, GetForwardTransform()); + if (angle < smallestAngle) + { + lockedTarget = scannedTargets[i]; + smallestAngle = angle; + } + + ActiveRadar = true; + return; + } + } + } + + if (lockedTarget.exists) + { + radarTarget = lockedTarget; + TargetAcquired = true; + radarLOALSearching = false; + TargetPosition = radarTarget.predictedPositionWithChaffFactor + (radarTarget.velocity * Time.fixedDeltaTime); + TargetVelocity = radarTarget.velocity; + TargetAcceleration = radarTarget.acceleration; + + if (!ActiveRadar && Time.time - TimeFired > 1) + { + if (weaponClass == WeaponClasses.SLW) + RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.Torpedo, 2f); + else + RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); + + Debug.Log("[BDArmory]: Pitbull! Radar missileBase has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); + } + return; + } + else + { + TargetAcquired = true; + TargetPosition = transform.position + (startDirection * 500); + TargetVelocity = Vector3.zero; + TargetAcceleration = Vector3.zero; + radarLOALSearching = true; + _radarFailTimer += Time.fixedDeltaTime; + if (_radarFailTimer > maxRadarFailTime) + { + Debug.Log("[BDArmory]: Active Radar guidance failed. LOAL could not lock a target."); + radarTarget = TargetSignatureData.noTarget; + legacyTargetVessel = null; + radarLOALSearching = false; + TargetAcquired = false; + ActiveRadar = false; + } + return; + } + } + + if (!radarTarget.exists) + { + legacyTargetVessel = null; + } + } + + protected bool CheckTargetEngagementEnvelope(TargetInfo ti) + { + return (ti.isMissile && engageMissile) || + (!ti.isMissile && ti.isFlying && engageAir) || + ((ti.isLandedOrSurfaceSplashed || ti.isSplashed) && engageGround) || + (ti.isUnderwater && engageSLW); + } + + protected void ReceiveRadarPing(Vessel v, Vector3 source, RadarWarningReceiver.RWRThreatTypes type, float persistTime) + { + if (TargetingMode == TargetingModes.AntiRad && TargetAcquired && v == vessel) + { + if ((source - VectorUtils.GetWorldSurfacePostion(targetGPSCoords, vessel.mainBody)).sqrMagnitude < Mathf.Pow(maxStaticLaunchRange / 4, 2) //drastically increase update range for anti-radiation missile to track moving targets! + && Vector3.Angle(source - transform.position, GetForwardTransform()) < maxOffBoresight) + { + TargetAcquired = true; + TargetPosition = source; + targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(TargetPosition, vessel.mainBody); + TargetVelocity = Vector3.zero; + TargetAcceleration = Vector3.zero; + lockFailTimer = 0; + } + } + } + + protected void UpdateAntiRadiationTarget() + { + if (!TargetAcquired) + { + guidanceActive = false; + return; + } + + if (FlightGlobals.ready) + { + if (lockFailTimer < 0) + { + lockFailTimer = 0; + } + lockFailTimer += Time.fixedDeltaTime; + } + + if (lockFailTimer > 8) + { + guidanceActive = false; + TargetAcquired = false; + } + else + { + TargetPosition = VectorUtils.GetWorldSurfacePostion(targetGPSCoords, vessel.mainBody); + } + } + + public void DrawDebugLine(Vector3 start, Vector3 end, Color color = default(Color)) + { + if (BDArmorySettings.DRAW_DEBUG_LINES) + { + if (!gameObject.GetComponent()) + { + LR = gameObject.AddComponent(); + LR.material = new Material(Shader.Find("KSP/Emissive/Diffuse")); + LR.material.SetColor("_EmissiveColor", color); + } + else + { + LR = gameObject.GetComponent(); + } + LR.positionCount = 2; + LR.SetPosition(0, start); + LR.SetPosition(1, end); + } + } + + protected void CheckDetonationDistance() + { + if (DetonationDistanceState == DetonationDistanceStates.Detonate) + { + Debug.Log("[BDArmory]: Target detected inside sphere - detonating"); + + Detonate(); + } + } + + protected Vector3 CalculateAGMBallisticGuidance(MissileBase missile, Vector3 targetPosition) + { + if (this._guidance == null) + { + _guidance = new BallisticGuidance(); + } + + return _guidance.GetDirection(this, targetPosition); + } + + + + + + protected void drawLabels() + { + if (vessel == null || !vessel.isActiveVessel) return; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + GUI.Label(new Rect(200, Screen.height - 200, 400, 400), this.shortName + ":" + debugString.ToString()); + } + } + + public float GetTntMass() + { + return vessel.FindPartModulesImplementing().Max(x => x.tntMass); + } + + public void CheckDetonationState() + { + //Guard clauses + if (!TargetAcquired) return; + + var targetDistancePerFrame = TargetVelocity * Time.fixedDeltaTime; + var missileDistancePerFrame = vessel.Velocity() * Time.fixedDeltaTime; + + var futureTargetPosition = (TargetPosition + targetDistancePerFrame); + var futureMissilePosition = (vessel.CoM + missileDistancePerFrame); + + var relativeSpeed = (TargetVelocity - vessel.Velocity()).magnitude * Time.fixedDeltaTime; + + switch (DetonationDistanceState) + { + case DetonationDistanceStates.NotSafe: + //Lets check if we are at a safe distance from the source vessel + + using (var hitsEnu = Physics.OverlapSphere(futureMissilePosition, GetBlastRadius() * 3f, 557057).AsEnumerable().GetEnumerator()) + { + while (hitsEnu.MoveNext()) + { + if (hitsEnu.Current == null) continue; + try + { + Part partHit = hitsEnu.Current.GetComponentInParent(); + + if (partHit?.vessel == SourceVessel) + { + //We found a hit to the vessel + return; + } + } + catch + { + // ignored + } + } + } + + //We are safe and we can continue with the cruising phase + + DetonationDistanceState = DetonationDistanceStates.Cruising; + break; + + case DetonationDistanceStates.Cruising: + + if (Vector3.Distance(futureMissilePosition, futureTargetPosition) < GetBlastRadius() * 10) + { + //We are now close enough to start checking the detonation distance + DetonationDistanceState = DetonationDistanceStates.CheckingProximity; + } + else + { + BDModularGuidance bdModularGuidance = this as BDModularGuidance; + + if (bdModularGuidance == null) return; + + if (Vector3.Distance(futureMissilePosition, futureTargetPosition) > this.DetonationDistance) return; + + DetonationDistanceState = DetonationDistanceStates.CheckingProximity; + } + break; + + case DetonationDistanceStates.CheckingProximity: + + if (DetonationDistance == 0) + { + if (weaponClass == WeaponClasses.Bomb) return; + + if (TimeIndex > 1f) + { + //Vector3 floatingorigin_current = FloatingOrigin.Offset; + + Ray rayFuturePosition = new Ray(vessel.CoM, futureMissilePosition); + + var hitsFuture = Physics.RaycastAll(rayFuturePosition, (float)missileDistancePerFrame.magnitude, 557057).AsEnumerable(); + + using (var hitsEnu = hitsFuture.GetEnumerator()) + { + while (hitsEnu.MoveNext()) + { + RaycastHit hit = hitsEnu.Current; + + try + { + var hitPart = hit.collider.gameObject.GetComponentInParent(); + + if (hitPart?.vessel != SourceVessel && hitPart?.vessel != vessel) + { + //We found a hit to other vessel + vessel.SetPosition(hit.point); + DetonationDistanceState = DetonationDistanceStates.Detonate; + Detonate(); + return; + } + } + catch + { + // ignored + } + } + } + } + + previousPos = part.transform.position; + } + else + { + float optimalDistance = (float)(Math.Max(DetonationDistance, relativeSpeed)); + + using (var hitsEnu = Physics.OverlapSphere(vessel.CoM, optimalDistance, 557057).AsEnumerable().GetEnumerator()) + { + while (hitsEnu.MoveNext()) + { + if (hitsEnu.Current == null) continue; + + try + { + Part partHit = hitsEnu.Current.GetComponentInParent(); + + if (partHit?.vessel == vessel || partHit?.vessel == SourceVessel) continue; + + Debug.Log("[BDArmory]: Missile proximity sphere hit | Distance overlap = " + optimalDistance + "| Part name = " + partHit.name); + + //We found a hit a different vessel than ours + DetonationDistanceState = DetonationDistanceStates.Detonate; + return; + } + catch + { + // ignored + } + } + } + } + + break; + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: DetonationDistanceState = : " + DetonationDistanceState); + } + } + + protected void SetInitialDetonationDistance() + { + if (this.DetonationDistance == -1) + { + if (GuidanceMode == GuidanceModes.AAMLead || GuidanceMode == GuidanceModes.AAMPure) + { + DetonationDistance = GetBlastRadius() * 0.25f; + } + else + { + //DetonationDistance = GetBlastRadius() * 0.05f; + DetonationDistance = 0f; + } + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: DetonationDistance = : " + DetonationDistance); + } + } + + protected void CollisionEnter(Collision col) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Missile Collided"); + + if (TimeIndex > 2 && HasFired && col.collider.gameObject.GetComponentInParent().GetFireFX()) + { + ContactPoint contact = col.contacts[0]; + Vector3 pos = contact.point; + BulletHitFX.AttachFlames(pos, col.collider.gameObject.GetComponentInParent()); + } + + if (HasExploded || !HasFired) return; + + if (DetonationDistanceState != DetonationDistanceStates.CheckingProximity) return; + + Debug.Log("[BDArmory]: Missile Collided - Triggering Detonation"); + Detonate(); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_ChangetoLowAltitudeRange", active = true)]//Change to Low Altitude Range + public void CruiseAltitudeRange() + { + if (Events["CruiseAltitudeRange"].guiName == "Change to Low Altitude Range") + { + Events["CruiseAltitudeRange"].guiName = "Change to High Altitude Range"; + + UI_FloatRange cruiseAltitudField = (UI_FloatRange)Fields["CruiseAltitude"].uiControlEditor; + cruiseAltitudField.maxValue = 500f; + cruiseAltitudField.minValue = 1f; + cruiseAltitudField.stepIncrement = 5f; + } + else + { + Events["CruiseAltitudeRange"].guiName = "Change to Low Altitude Range"; + UI_FloatRange cruiseAltitudField = (UI_FloatRange)Fields["CruiseAltitude"].uiControlEditor; + cruiseAltitudField.maxValue = 25000f; + cruiseAltitudField.minValue = 500; + cruiseAltitudField.stepIncrement = 500f; + } + this.part.RefreshAssociatedWindows(); + } + } +} diff --git a/BDArmory/Modules/MissileFire.cs b/BDArmory/Modules/MissileFire.cs new file mode 100644 index 000000000..3bb1d0265 --- /dev/null +++ b/BDArmory/Modules/MissileFire.cs @@ -0,0 +1,4573 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using BDArmory.Control; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.CounterMeasure; +using BDArmory.Guidances; +using BDArmory.Misc; +using BDArmory.Parts; +using BDArmory.Radar; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class MissileFire : PartModule + { + #region Declarations + + //weapons + private const int LIST_CAPACITY = 100; + private List weaponTypes = new List(LIST_CAPACITY); + public IBDWeapon[] weaponArray; + + // extension for feature_engagementenvelope: specific lists by weapon engagement type + private List weaponTypesAir = new List(LIST_CAPACITY); + private List weaponTypesMissile = new List(LIST_CAPACITY); + private List weaponTypesGround = new List(LIST_CAPACITY); + private List weaponTypesSLW = new List(LIST_CAPACITY); + + [KSPField(guiActiveEditor = false, isPersistant = true, guiActive = false)] public int weaponIndex; + + //ScreenMessage armedMessage; + ScreenMessage selectionMessage; + string selectionText = ""; + + Transform cameraTransform; + + float startTime; + int missilesAway; + + public bool hasLoadedRippleData; + float rippleTimer; + + public TargetSignatureData heatTarget; + + //[KSPField(isPersistant = true)] + public float rippleRPM + { + get + { + if (selectedWeapon != null) + { + return rippleDictionary[selectedWeapon.GetShortName()].rpm; + } + else + { + return 0; + } + } + set + { + if (selectedWeapon != null) + { + if (rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) + { + rippleDictionary[selectedWeapon.GetShortName()].rpm = value; + } + else + { + return; + } + } + else + { + return; + } + } + } + + float triggerTimer; + int rippleGunCount; + int _gunRippleIndex; + public float gunRippleRpm; + + public int gunRippleIndex + { + get { return _gunRippleIndex; } + set + { + _gunRippleIndex = value; + if (_gunRippleIndex >= rippleGunCount) + { + _gunRippleIndex = 0; + } + } + } + + //ripple stuff + string rippleData = string.Empty; + Dictionary rippleDictionary; //weapon name, ripple option + public bool canRipple; + + //public float triggerHoldTime = 0.3f; + + //[KSPField(isPersistant = true)] + + public bool rippleFire + { + get + { + if (selectedWeapon == null) return false; + if (rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) + { + return rippleDictionary[selectedWeapon.GetShortName()].rippleFire; + } + //rippleDictionary.Add(selectedWeapon.GetShortName(), new RippleOption(false, 650)); + return false; + } + } + + public void ToggleRippleFire() + { + if (selectedWeapon != null) + { + RippleOption ro; + if (rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) + { + ro = rippleDictionary[selectedWeapon.GetShortName()]; + } + else + { + ro = new RippleOption(false, 650); //default to true ripple fire for guns, otherwise, false + if (selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) + { + ro.rippleFire = currentGun.useRippleFire; + } + rippleDictionary.Add(selectedWeapon.GetShortName(), ro); + } + + ro.rippleFire = !ro.rippleFire; + + if (selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) + { + List.Enumerator w = vessel.FindPartModulesImplementing().GetEnumerator(); + while (w.MoveNext()) + { + if (w.Current == null) continue; + if (w.Current.GetShortName() == selectedWeapon.GetShortName()) + w.Current.useRippleFire = ro.rippleFire; + } + w.Dispose(); + } + } + } + + public void AGToggleRipple(KSPActionParam param) + { + ToggleRippleFire(); + } + + void ParseRippleOptions() + { + rippleDictionary = new Dictionary(); + //Debug.Log("[BDArmory]: Parsing ripple options"); + if (!string.IsNullOrEmpty(rippleData)) + { + //Debug.Log("[BDArmory]: Ripple data: " + rippleData); + try + { + IEnumerator weapon = rippleData.Split(new char[] { ';' }).AsEnumerable().GetEnumerator(); ; + while (weapon.MoveNext()) + { + if (weapon.Current == string.Empty) continue; + + string[] options = weapon.Current.Split(new char[] { ',' }); + string wpnName = options[0]; + bool rf = bool.Parse(options[1]); + float rpm = float.Parse(options[2]); + RippleOption ro = new RippleOption(rf, rpm); + rippleDictionary.Add(wpnName, ro); + } + weapon.Dispose(); + } + catch (Exception) + { + //Debug.Log("[BDArmory]: Ripple data was invalid."); + rippleData = string.Empty; + } + } + else + { + //Debug.Log("[BDArmory]: Ripple data is empty."); + } + + if (vessel) + { + List.Enumerator rl = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rl.MoveNext()) + { + if (rl.Current == null) continue; + if (!rippleDictionary.ContainsKey(rl.Current.GetShortName())) + { + rippleDictionary.Add(rl.Current.GetShortName(), new RippleOption(false, 650f)); + } + } + rl.Dispose(); + } + hasLoadedRippleData = true; + } + + void SaveRippleOptions(ConfigNode node) + { + if (rippleDictionary != null) + { + rippleData = string.Empty; + Dictionary.KeyCollection.Enumerator wpnName = rippleDictionary.Keys.GetEnumerator(); + while (wpnName.MoveNext()) + { + if (wpnName.Current == null) continue; + rippleData += $"{wpnName},{rippleDictionary[wpnName.Current].rippleFire},{rippleDictionary[wpnName.Current].rpm};"; + } + wpnName.Dispose(); + node.SetValue("RippleData", rippleData, true); + } + //Debug.Log("[BDArmory]: Saved ripple data"); + } + + public bool hasSingleFired; + + //bomb aimer + Part bombPart; + Vector3 bombAimerPosition = Vector3.zero; + Texture2D bombAimerTexture = GameDatabase.Instance.GetTexture("BDArmory/Textures/grayCircle", false); + bool showBombAimer; + + //targeting + private List loadedVessels = new List(); + float targetListTimer; + + //rocket aimer handling + RocketLauncher currentRocket; + + //sounds + AudioSource audioSource; + public AudioSource warningAudioSource; + AudioSource targetingAudioSource; + AudioClip clickSound; + AudioClip warningSound; + AudioClip armOnSound; + AudioClip armOffSound; + AudioClip heatGrowlSound; + bool warningSounding; + + //missile warning + public bool missileIsIncoming; + public float incomingMissileDistance = float.MaxValue; + public Vessel incomingMissileVessel; + + //guard mode vars + float targetScanTimer; + Vessel guardTarget; + public TargetInfo currentTarget; + TargetInfo overrideTarget; //used for setting target next guard scan for stuff like assisting teammates + float overrideTimer; + + public bool TargetOverride + { + get { return overrideTimer > 0; } + } + + //AIPilot + public IBDAIControl AI; + + // some extending related code still uses pilotAI, which is implementation specific and does not make sense to include in the interface + private BDModulePilotAI pilotAI { get { return AI as BDModulePilotAI; } } + + public float timeBombReleased; + + //targeting pods + public ModuleTargetingCamera mainTGP = null; + public List targetingPods = new List(); + + //radar + public List radars = new List(); + public VesselRadarData vesselRadarData; + + //jammers + public List jammers = new List(); + + //other modules + public List wmModules = new List(); + + //wingcommander + public ModuleWingCommander wingCommander; + + //RWR + private RadarWarningReceiver radarWarn; + + public RadarWarningReceiver rwr + { + get + { + if (!radarWarn || radarWarn.vessel != vessel) + { + return null; + } + return radarWarn; + } + set { radarWarn = value; } + } + + //GPS + public GPSTargetInfo designatedGPSInfo; + + public Vector3d designatedGPSCoords => designatedGPSInfo.gpsCoordinates; + + //weapon slaving + public bool slavingTurrets = false; + public Vector3 slavedPosition; + public Vector3 slavedVelocity; + public Vector3 slavedAcceleration; + public TargetSignatureData slavedTarget; + + //current weapon ref + public MissileBase CurrentMissile; + + public ModuleWeapon currentGun + { + get + { + if (selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) + { + return selectedWeapon.GetPart().FindModuleImplementing(); + } + else + { + return null; + } + } + } + + public bool underAttack; + public bool underFire; + Coroutine ufRoutine; + + public Vector3 incomingThreatPosition; + public Vessel incomingThreatVessel; + + bool guardFiringMissile; + bool disabledRocketAimers; + bool antiRadTargetAcquired; + Vector3 antiRadiationTarget; + bool laserPointDetected; + + ModuleTargetingCamera foundCam; + + #region KSPFields,events,actions + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_FiringInterval"),//Firing Interval + UI_FloatRange(minValue = 1f, maxValue = 60f, stepIncrement = 1f, scene = UI_Scene.All)] + public float + targetScanInterval = 3; + + // extension for feature_engagementenvelope: burst length for guns + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_FiringBurstLength"),//Firing Burst Length + UI_FloatRange(minValue = 0f, maxValue = 60f, stepIncrement = 0.5f, scene = UI_Scene.All)] + public float fireBurstLength = 0; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_FieldOfView"),//Field of View + UI_FloatRange(minValue = 10f, maxValue = 360f, stepIncrement = 10f, scene = UI_Scene.All)] + public float + guardAngle = 360; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_VisualRange"),//Visual Range + UI_FloatRange(minValue = 100f, maxValue = 5000, stepIncrement = 100f, scene = UI_Scene.All)] + public float + guardRange = 10000; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_GunsRange"),//Guns Range + UI_FloatRange(minValue = 0f, maxValue = 10000f, stepIncrement = 10f, scene = UI_Scene.All)] + public float + gunRange = 2500f; + + public const float maxAllowableMissilesOnTarget = 18f; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MissilesORTarget"), UI_FloatRange(minValue = 1f, maxValue = maxAllowableMissilesOnTarget, stepIncrement = 1f, scene = UI_Scene.All)]//Missiles/Target + public float maxMissilesOnTarget = 1; + + public void ToggleGuardMode() + { + guardMode = !guardMode; + + if (!guardMode) + { + //disable turret firing and guard mode + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + weapon.Current.visualTargetVessel = null; + weapon.Current.autoFire = false; + weapon.Current.aiControlled = false; + } + weapon.Dispose(); + weaponIndex = 0; + selectedWeapon = null; + } + } + + [KSPAction("Toggle Guard Mode")] + public void AGToggleGuardMode(KSPActionParam param) + { + ToggleGuardMode(); + } + + //[KSPField(isPersistant = true)] public bool guardMode; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_GaurdMode"),//Gaurd Mode: + UI_Toggle(disabledText = "OFF", enabledText = "ON")] + public bool guardMode; + + //[KSPField(isPersistant = false, guiActive = false, guiActiveEditor = false, guiName = "Target Type: "), UI_Toggle(disabledText = "Vessels", enabledText = "Missiles")] + public bool targetMissiles = false; + + [KSPAction("Toggle Target Type")] + public void AGToggleTargetType(KSPActionParam param) + { + ToggleTargetType(); + } + + public void ToggleTargetType() + { + targetMissiles = !targetMissiles; + audioSource.PlayOneShot(clickSound); + } + + [KSPAction("Jettison Weapon")] + public void AGJettisonWeapon(KSPActionParam param) + { + if (CurrentMissile) + { + List.Enumerator missile = vessel.FindPartModulesImplementing().GetEnumerator(); + while (missile.MoveNext()) + { + if (missile.Current == null) continue; + if (missile.Current.GetShortName() == CurrentMissile.GetShortName()) + { + missile.Current.Jettison(); + } + } + missile.Dispose(); + } + else if (selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) + { + List.Enumerator rocket = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rocket.MoveNext()) + { + if (rocket.Current == null) continue; + rocket.Current.Jettison(); + } + rocket.Dispose(); + } + } + + public BDTeam Team + { + get + { + return BDTeam.Get(teamString); + } + set + { + if (!team_loaded) return; + if (!BDArmorySetup.Instance.Teams.ContainsKey(value.Name)) + BDArmorySetup.Instance.Teams.Add(value.Name, value); + teamString = value.Name; + team = value.Serialize(); + } + } + + // Team name + [KSPField(guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_Team")]//Team + public string teamString = "Neutral"; + + // Serialized team + [KSPField(isPersistant = true)] + public string team; + private bool team_loaded = false; + + [KSPAction("Next Team")] + public void AGNextTeam(KSPActionParam param) + { + NextTeam(); + } + + public delegate void ChangeTeamDelegate(MissileFire wm, BDTeam team); + + public static event ChangeTeamDelegate OnChangeTeam; + + public void SetTeam(BDTeam team) + { + if (HighLogic.LoadedSceneIsFlight) + { + using (var wpnMgr = vessel.FindPartModulesImplementing().GetEnumerator()) + while (wpnMgr.MoveNext()) + { + if (wpnMgr.Current == null) continue; + wpnMgr.Current.Team = team; + } + + if (vessel.gameObject.GetComponent()) + { + BDATargetManager.RemoveTarget(vessel.gameObject.GetComponent()); + Destroy(vessel.gameObject.GetComponent()); + } + OnChangeTeam?.Invoke(this, Team); + ResetGuardInterval(); + } + else if (HighLogic.LoadedSceneIsEditor) + { + using (var editorPart = EditorLogic.fetch.ship.Parts.GetEnumerator()) + while (editorPart.MoveNext()) + using (var wpnMgr = editorPart.Current.FindModulesImplementing().GetEnumerator()) + while (wpnMgr.MoveNext()) + { + if (wpnMgr.Current == null) continue; + wpnMgr.Current.Team = team; + } + } + } + + [KSPEvent(active = true, guiActiveEditor = true, guiActive = false)] + public void NextTeam() + { + var teamList = new List { "A", "B" }; + using (var teams = BDArmorySetup.Instance.Teams.GetEnumerator()) + while (teams.MoveNext()) + if (!teamList.Contains(teams.Current.Key) && !teams.Current.Value.Neutral) + teamList.Add(teams.Current.Key); + teamList.Sort(); + SetTeam(BDTeam.Get(teamList[(teamList.IndexOf(Team.Name) + 1) % teamList.Count])); + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, active = true, guiName = "#LOC_BDArmory_SelectTeam")]//Select Team + public void SelectTeam() + { + BDTeamSelector.Instance.Open(this, new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)); + } + + [KSPField(isPersistant = true)] + public bool isArmed = false; + + [KSPAction("Arm/Disarm")] + public void AGToggleArm(KSPActionParam param) + { + ToggleArm(); + } + + public void ToggleArm() + { + isArmed = !isArmed; + if (isArmed) audioSource.PlayOneShot(armOnSound); + else audioSource.PlayOneShot(armOffSound); + } + + [KSPField(isPersistant = false, guiActive = true, guiName = "#LOC_BDArmory_Weapon")]//Weapon + public string selectedWeaponString = + "None"; + + IBDWeapon sw; + + public IBDWeapon selectedWeapon + { + get + { + if ((sw != null && sw.GetPart().vessel == vessel) || weaponIndex <= 0) return sw; + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (weapon.Current.GetShortName() != selectedWeaponString) continue; + sw = weapon.Current; + break; + } + weapon.Dispose(); + return sw; + } + set + { + if (sw == value) return; + sw = value; + selectedWeaponString = GetWeaponName(value); + UpdateSelectedWeaponState(); + } + } + + [KSPAction("Fire Missile")] + public void AGFire(KSPActionParam param) + { + FireMissile(); + } + + [KSPAction("Fire Guns (Hold)")] + public void AGFireGunsHold(KSPActionParam param) + { + if (weaponIndex <= 0 || (selectedWeapon.GetWeaponClass() != WeaponClasses.Gun && + selectedWeapon.GetWeaponClass() != WeaponClasses.DefenseLaser)) return; + List.Enumerator weap = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weap.MoveNext()) + { + if (weap.Current == null) continue; + if (weap.Current.weaponState != ModuleWeapon.WeaponStates.Enabled || + weap.Current.GetShortName() != selectedWeapon.GetShortName()) continue; + weap.Current.AGFireHold(param); + } + weap.Dispose(); + } + + [KSPAction("Fire Guns (Toggle)")] + public void AGFireGunsToggle(KSPActionParam param) + { + if (weaponIndex <= 0 || (selectedWeapon.GetWeaponClass() != WeaponClasses.Gun && + selectedWeapon.GetWeaponClass() != WeaponClasses.DefenseLaser)) return; + List.Enumerator weap = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weap.MoveNext()) + { + if (weap.Current == null) continue; + if (weap.Current.weaponState != ModuleWeapon.WeaponStates.Enabled || + weap.Current.GetShortName() != selectedWeapon.GetShortName()) continue; + weap.Current.AGFireToggle(param); + } + weap.Dispose(); + } + + [KSPAction("Next Weapon")] + public void AGCycle(KSPActionParam param) + { + CycleWeapon(true); + } + + [KSPAction("Previous Weapon")] + public void AGCycleBack(KSPActionParam param) + { + CycleWeapon(false); + } + + [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_OpenGUI", active = true)]//Open GUI + public void ToggleToolbarGUI() + { + BDArmorySetup.windowBDAToolBarEnabled = !BDArmorySetup.windowBDAToolBarEnabled; + } + + #endregion KSPFields,events,actions + + #endregion Declarations + + #region KSP Events + + public override void OnSave(ConfigNode node) + { + base.OnSave(node); + + if (HighLogic.LoadedSceneIsFlight) + { + SaveRippleOptions(node); + } + } + + public override void OnLoad(ConfigNode node) + { + base.OnLoad(node); + if (HighLogic.LoadedSceneIsFlight) + { + rippleData = string.Empty; + if (node.HasValue("RippleData")) + { + rippleData = node.GetValue("RippleData"); + } + ParseRippleOptions(); + } + } + + public override void OnAwake() + { + clickSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/click"); + warningSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/warning"); + armOnSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/armOn"); + armOffSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/armOff"); + heatGrowlSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/heatGrowl"); + + //HEAT LOCKING + heatTarget = TargetSignatureData.noTarget; + } + + public void Start() + { + team_loaded = true; + Team = BDTeam.Deserialize(team); + + UpdateMaxGuardRange(); + + startTime = Time.time; + + if (HighLogic.LoadedSceneIsFlight) + { + part.force_activate(); + + selectionMessage = new ScreenMessage("", 2.0f, ScreenMessageStyle.LOWER_CENTER); + + UpdateList(); + if (weaponArray.Length > 0) selectedWeapon = weaponArray[weaponIndex]; + //selectedWeaponString = GetWeaponName(selectedWeapon); + + cameraTransform = part.FindModelTransform("BDARPMCameraTransform"); + + part.force_activate(); + rippleTimer = Time.time; + targetListTimer = Time.time; + + wingCommander = part.FindModuleImplementing(); + + audioSource = gameObject.AddComponent(); + audioSource.minDistance = 1; + audioSource.maxDistance = 500; + audioSource.dopplerLevel = 0; + audioSource.spatialBlend = 1; + + warningAudioSource = gameObject.AddComponent(); + warningAudioSource.minDistance = 1; + warningAudioSource.maxDistance = 500; + warningAudioSource.dopplerLevel = 0; + warningAudioSource.spatialBlend = 1; + + targetingAudioSource = gameObject.AddComponent(); + targetingAudioSource.minDistance = 1; + targetingAudioSource.maxDistance = 250; + targetingAudioSource.dopplerLevel = 0; + targetingAudioSource.loop = true; + targetingAudioSource.spatialBlend = 1; + + StartCoroutine(MissileWarningResetRoutine()); + + if (vessel.isActiveVessel) + { + BDArmorySetup.Instance.ActiveWeaponManager = this; + } + + UpdateVolume(); + BDArmorySetup.OnVolumeChange += UpdateVolume; + BDArmorySetup.OnSavedSettings += ClampVisualRange; + + StartCoroutine(StartupListUpdater()); + missilesAway = 0; + + GameEvents.onVesselCreate.Add(OnVesselCreate); + GameEvents.onPartJointBreak.Add(OnPartJointBreak); + GameEvents.onPartDie.Add(OnPartDie); + + List.Enumerator aipilot = vessel.FindPartModulesImplementing().GetEnumerator(); + while (aipilot.MoveNext()) + { + if (aipilot.Current == null) continue; + AI = aipilot.Current; + break; + } + aipilot.Dispose(); + + RefreshModules(); + } + } + + void OnPartDie(Part p = null) + { + if (p == part) + { + try + { + GameEvents.onPartDie.Remove(OnPartDie); + GameEvents.onPartJointBreak.Remove(OnPartJointBreak); + GameEvents.onVesselCreate.Remove(OnVesselCreate); + } + catch (Exception e) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) Debug.Log("[BDArmory]: Error OnPartDie: " + e.Message); + } + } + RefreshModules(); + UpdateList(); + } + + void OnVesselCreate(Vessel v) + { + RefreshModules(); + } + + void OnPartJointBreak(PartJoint j, float breakForce) + { + if (!part) + { + GameEvents.onPartJointBreak.Remove(OnPartJointBreak); + } + + if ((j.Parent && j.Parent.vessel == vessel) || (j.Child && j.Child.vessel == vessel)) + { + RefreshModules(); + UpdateList(); + } + } + + public override void OnUpdate() + { + if (!HighLogic.LoadedSceneIsFlight) + { + return; + } + + base.OnUpdate(); + if (!vessel.packed) + { + if (weaponIndex >= weaponArray.Length) + { + hasSingleFired = true; + triggerTimer = 0; + + weaponIndex = Mathf.Clamp(weaponIndex, 0, weaponArray.Length - 1); + + DisplaySelectedWeaponMessage(); + } + if (weaponArray.Length > 0 && selectedWeapon != weaponArray[weaponIndex]) + selectedWeapon = weaponArray[weaponIndex]; + + //finding next rocket to shoot (for aimer) + //FindNextRocket(); + + //targeting + if (weaponIndex > 0 && + (selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || + selectedWeapon.GetWeaponClass() == WeaponClasses.SLW || + selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb)) + { + SearchForLaserPoint(); + SearchForHeatTarget(); + SearchForRadarSource(); + } + + CalculateMissilesAway(); + } + + UpdateTargetingAudio(); + + if (vessel.isActiveVessel) + { + if (!CheckMouseIsOnGui() && isArmed && BDInputUtils.GetKey(BDInputSettingsFields.WEAP_FIRE_KEY)) + { + triggerTimer += Time.fixedDeltaTime; + } + else + { + triggerTimer = 0; + hasSingleFired = false; + } + + //firing missiles and rockets=== + if (!guardMode && + selectedWeapon != null && + (selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket + || selectedWeapon.GetWeaponClass() == WeaponClasses.Missile + || selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb + || selectedWeapon.GetWeaponClass() == WeaponClasses.SLW + )) + { + canRipple = true; + if (!MapView.MapIsEnabled && triggerTimer > BDArmorySettings.TRIGGER_HOLD_TIME && !hasSingleFired) + { + if (rippleFire) + { + if (Time.time - rippleTimer > 60f / rippleRPM) + { + FireMissile(); + rippleTimer = Time.time; + } + } + else + { + FireMissile(); + hasSingleFired = true; + } + } + } + else if (!guardMode && + selectedWeapon != null && + (selectedWeapon.GetWeaponClass() == WeaponClasses.Gun && currentGun.roundsPerMinute < 1500)) + { + canRipple = true; + } + else + { + canRipple = false; + } + } + } + + private void CalculateMissilesAway() + { + int tempMissilesAway = 0; + List.Enumerator firedMissiles = BDATargetManager.FiredMissiles.GetEnumerator(); + + while (firedMissiles.MoveNext()) + { + if (firedMissiles.Current == null) continue; + + var missileBase = firedMissiles.Current as MissileBase; + + if (missileBase.SourceVessel != this.vessel) continue; + + if (missileBase.MissileState != MissileBase.MissileStates.PostThrust && !missileBase.HasMissed && !missileBase.HasExploded) + { + tempMissilesAway++; + } + } + + this.missilesAway = tempMissilesAway; + } + + public override void OnFixedUpdate() + { + if (guardMode && vessel.IsControllable) + { + GuardMode(); + } + else + { + targetScanTimer = -100; + } + BombAimer(); + } + + void OnDestroy() + { + BDArmorySetup.OnVolumeChange -= UpdateVolume; + BDArmorySetup.OnSavedSettings -= ClampVisualRange; + GameEvents.onVesselCreate.Remove(OnVesselCreate); + GameEvents.onPartJointBreak.Remove(OnPartJointBreak); + GameEvents.onPartDie.Remove(OnPartDie); + } + + void ClampVisualRange() + { + guardRange = Mathf.Clamp(guardRange, 0, BDArmorySettings.MAX_GUARD_VISUAL_RANGE); + } + + void OnGUI() + { + if (HighLogic.LoadedSceneIsFlight && vessel == FlightGlobals.ActiveVessel && + BDArmorySetup.GAME_UI_ENABLED && !MapView.MapIsEnabled) + { + if (BDArmorySettings.DRAW_DEBUG_LINES) + { + if (incomingMissileVessel) + { + BDGUIUtils.DrawLineBetweenWorldPositions(part.transform.position, + incomingMissileVessel.transform.position, 5, Color.cyan); + } + } + + if (showBombAimer) + { + MissileBase ml = CurrentMissile; + if (ml) + { + float size = 128; + Texture2D texture = BDArmorySetup.Instance.greenCircleTexture; + + if ((ml is MissileLauncher && ((MissileLauncher)ml).guidanceActive) || ml is BDModularGuidance) + { + texture = BDArmorySetup.Instance.largeGreenCircleTexture; + size = 256; + } + BDGUIUtils.DrawTextureOnWorldPos(bombAimerPosition, texture, new Vector2(size, size), 0); + } + } + + //MISSILE LOCK HUD + MissileBase missile = CurrentMissile; + if (missile) + { + if (missile.TargetingMode == MissileBase.TargetingModes.Laser) + { + if (laserPointDetected && foundCam) + { + BDGUIUtils.DrawTextureOnWorldPos(foundCam.groundTargetPosition, BDArmorySetup.Instance.greenCircleTexture, new Vector2(48, 48), 1); + } + + List.Enumerator cam = BDATargetManager.ActiveLasers.GetEnumerator(); + while (cam.MoveNext()) + { + if (cam.Current == null) continue; + if (cam.Current.vessel != vessel && cam.Current.surfaceDetected && cam.Current.groundStabilized && !cam.Current.gimbalLimitReached) + { + BDGUIUtils.DrawTextureOnWorldPos(cam.Current.groundTargetPosition, BDArmorySetup.Instance.greenDiamondTexture, new Vector2(18, 18), 0); + } + } + cam.Dispose(); + } + else if (missile.TargetingMode == MissileBase.TargetingModes.Heat) + { + MissileBase ml = CurrentMissile; + if (heatTarget.exists) + { + BDGUIUtils.DrawTextureOnWorldPos(heatTarget.position, BDArmorySetup.Instance.greenCircleTexture, new Vector2(36, 36), 3); + float distanceToTarget = Vector3.Distance(heatTarget.position, ml.MissileReferenceTransform.position); + BDGUIUtils.DrawTextureOnWorldPos(ml.MissileReferenceTransform.position + (distanceToTarget * ml.GetForwardTransform()), BDArmorySetup.Instance.largeGreenCircleTexture, new Vector2(128, 128), 0); + Vector3 fireSolution = MissileGuidance.GetAirToAirFireSolution(ml, heatTarget.position, heatTarget.velocity); + Vector3 fsDirection = (fireSolution - ml.MissileReferenceTransform.position).normalized; + BDGUIUtils.DrawTextureOnWorldPos(ml.MissileReferenceTransform.position + (distanceToTarget * fsDirection), BDArmorySetup.Instance.greenDotTexture, new Vector2(6, 6), 0); + } + else + { + BDGUIUtils.DrawTextureOnWorldPos(ml.MissileReferenceTransform.position + (2000 * ml.GetForwardTransform()), BDArmorySetup.Instance.greenCircleTexture, new Vector2(36, 36), 3); + BDGUIUtils.DrawTextureOnWorldPos(ml.MissileReferenceTransform.position + (2000 * ml.GetForwardTransform()), BDArmorySetup.Instance.largeGreenCircleTexture, new Vector2(156, 156), 0); + } + } + else if (missile.TargetingMode == MissileBase.TargetingModes.Radar) + { + MissileBase ml = CurrentMissile; + //if(radar && radar.locked) + if (vesselRadarData && vesselRadarData.locked) + { + float distanceToTarget = Vector3.Distance(vesselRadarData.lockedTargetData.targetData.predictedPosition, ml.MissileReferenceTransform.position); + BDGUIUtils.DrawTextureOnWorldPos(ml.MissileReferenceTransform.position + (distanceToTarget * ml.GetForwardTransform()), BDArmorySetup.Instance.dottedLargeGreenCircle, new Vector2(128, 128), 0); + //Vector3 fireSolution = MissileGuidance.GetAirToAirFireSolution(CurrentMissile, radar.lockedTarget.predictedPosition, radar.lockedTarget.velocity); + Vector3 fireSolution = MissileGuidance.GetAirToAirFireSolution(ml, vesselRadarData.lockedTargetData.targetData.predictedPosition, vesselRadarData.lockedTargetData.targetData.velocity); + Vector3 fsDirection = (fireSolution - ml.MissileReferenceTransform.position).normalized; + BDGUIUtils.DrawTextureOnWorldPos(ml.MissileReferenceTransform.position + (distanceToTarget * fsDirection), BDArmorySetup.Instance.greenDotTexture, new Vector2(6, 6), 0); + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + string dynRangeDebug = string.Empty; + MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(missile, vesselRadarData.lockedTargetData.targetData.velocity, vesselRadarData.lockedTargetData.targetData.predictedPosition); + dynRangeDebug += "MaxDLZ: " + dlz.maxLaunchRange; + dynRangeDebug += "\nMinDLZ: " + dlz.minLaunchRange; + GUI.Label(new Rect(800, 600, 200, 200), dynRangeDebug); + } + } + } + else if (missile.TargetingMode == MissileBase.TargetingModes.AntiRad) + { + if (rwr && rwr.rwrEnabled && rwr.displayRWR) + { + for (int i = 0; i < rwr.pingsData.Length; i++) + { + if (rwr.pingsData[i].exists && (rwr.pingsData[i].signalStrength == 0 || rwr.pingsData[i].signalStrength == 5) && Vector3.Dot(rwr.pingWorldPositions[i] - missile.transform.position, missile.GetForwardTransform()) > 0) + { + BDGUIUtils.DrawTextureOnWorldPos(rwr.pingWorldPositions[i], BDArmorySetup.Instance.greenDiamondTexture, new Vector2(22, 22), 0); + } + } + } + + if (antiRadTargetAcquired) + { + BDGUIUtils.DrawTextureOnWorldPos(antiRadiationTarget, + BDArmorySetup.Instance.openGreenSquare, new Vector2(22, 22), 0); + } + } + } + + if ((missile && missile.TargetingMode == MissileBase.TargetingModes.Gps) || BDArmorySetup.Instance.showingWindowGPS) + { + if (designatedGPSCoords != Vector3d.zero) + { + BDGUIUtils.DrawTextureOnWorldPos(VectorUtils.GetWorldSurfacePostion(designatedGPSCoords, vessel.mainBody), BDArmorySetup.Instance.greenSpikedPointCircleTexture, new Vector2(22, 22), 0); + } + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + GUI.Label(new Rect(600, 900, 100, 100), "Missiles away: " + missilesAway); + } + } + } + + bool CheckMouseIsOnGui() + { + return Misc.Misc.CheckMouseIsOnGui(); + } + + #endregion KSP Events + + #region Enumerators + + IEnumerator StartupListUpdater() + { + while (vessel.packed || !FlightGlobals.ready) + { + yield return null; + if (vessel.isActiveVessel) + { + BDArmorySetup.Instance.ActiveWeaponManager = this; + } + } + UpdateList(); + } + + IEnumerator MissileWarningResetRoutine() + { + while (enabled) + { + missileIsIncoming = false; + yield return new WaitForSeconds(1); + } + } + + IEnumerator UnderFireRoutine() + { + underFire = true; + yield return new WaitForSeconds(3); + underFire = false; + } + + IEnumerator UnderAttackRoutine() + { + underAttack = true; + yield return new WaitForSeconds(3); + underAttack = false; + } + + IEnumerator GuardTurretRoutine() + { + if (gameObject.activeInHierarchy) + //target is out of visual range, try using sensors + { + if (guardTarget.LandedOrSplashed) + { + if (targetingPods.Count > 0) + { + List.Enumerator tgp = targetingPods.GetEnumerator(); + while (tgp.MoveNext()) + { + if (tgp.Current == null) continue; + if (!tgp.Current.enabled || (tgp.Current.cameraEnabled && tgp.Current.groundStabilized && + !((tgp.Current.groundTargetPosition - + guardTarget.transform.position).sqrMagnitude > 20 * 20))) continue; + tgp.Current.EnableCamera(); + yield return StartCoroutine(tgp.Current.PointToPositionRoutine(guardTarget.CoM)); + //yield return StartCoroutine(tgp.Current.PointToPositionRoutine(TargetInfo.TargetCOMDispersion(guardTarget))); + if (!tgp.Current) continue; + if (tgp.Current.groundStabilized && guardTarget && + (tgp.Current.groundTargetPosition - guardTarget.transform.position).sqrMagnitude < 20 * 20) + { + tgp.Current.slaveTurrets = true; + StartGuardTurretFiring(); + yield break; + } + tgp.Current.DisableCamera(); + } + tgp.Dispose(); + } + + if (!guardTarget || (guardTarget.transform.position - transform.position).sqrMagnitude > guardRange * guardRange) + { + SetTarget(null); //disengage, sensors unavailable. + yield break; + } + } + else + { + if (!vesselRadarData || !(vesselRadarData.radarCount > 0)) + { + List.Enumerator rd = radars.GetEnumerator(); + while (rd.MoveNext()) + { + if (rd.Current == null) continue; + if (!rd.Current.canLock) continue; + rd.Current.EnableRadar(); + break; + } + rd.Dispose(); + } + + if (vesselRadarData && + (!vesselRadarData.locked || + (vesselRadarData.lockedTargetData.targetData.predictedPosition - guardTarget.transform.position) + .sqrMagnitude > 40 * 40)) + { + //vesselRadarData.TryLockTarget(guardTarget.transform.position); + vesselRadarData.TryLockTarget(guardTarget); + yield return new WaitForSeconds(0.5f); + if (guardTarget && vesselRadarData && vesselRadarData.locked && + vesselRadarData.lockedTargetData.vessel == guardTarget) + { + vesselRadarData.SlaveTurrets(); + StartGuardTurretFiring(); + yield break; + } + } + + if (!guardTarget || (guardTarget.transform.position - transform.position).sqrMagnitude > guardRange * guardRange) + { + SetTarget(null); //disengage, sensors unavailable. + yield break; + } + } + } + + StartGuardTurretFiring(); + yield break; + } + + IEnumerator ResetMissileThreatDistanceRoutine() + { + yield return new WaitForSeconds(8); + incomingMissileDistance = float.MaxValue; + } + + IEnumerator GuardMissileRoutine() + { + MissileBase ml = CurrentMissile; + + if (ml && !guardFiringMissile) + { + guardFiringMissile = true; + + if (ml.TargetingMode == MissileBase.TargetingModes.Radar && vesselRadarData) + { + float attemptLockTime = Time.time; + while ((!vesselRadarData.locked || (vesselRadarData.lockedTargetData.vessel != guardTarget)) && Time.time - attemptLockTime < 2) + { + if (vesselRadarData.locked) + { + vesselRadarData.UnlockAllTargets(); + yield return null; + } + //vesselRadarData.TryLockTarget(guardTarget.transform.position+(guardTarget.rb_velocity*Time.fixedDeltaTime)); + vesselRadarData.TryLockTarget(guardTarget); + yield return new WaitForSeconds(0.25f); + } + + if (ml && AIMightDirectFire() && vesselRadarData.locked) + { + SetCargoBays(); + float LAstartTime = Time.time; + while (AIMightDirectFire() && Time.time - LAstartTime < 3 && + GetLaunchAuthorization(guardTarget, this)) + { + yield return new WaitForFixedUpdate(); + } + + yield return new WaitForSeconds(0.5f); + } + + //wait for missile turret to point at target + //TODO BDModularGuidance: add turret + MissileLauncher mlauncher = ml as MissileLauncher; + if (mlauncher != null) + { + if (guardTarget && ml && mlauncher.missileTurret && vesselRadarData.locked) + { + vesselRadarData.SlaveTurrets(); + float turretStartTime = Time.time; + while (Time.time - turretStartTime < 5) + { + float angle = Vector3.Angle(mlauncher.missileTurret.finalTransform.forward, mlauncher.missileTurret.slavedTargetPosition - mlauncher.missileTurret.finalTransform.position); + if (angle < 1) + { + turretStartTime -= 2 * Time.fixedDeltaTime; + } + yield return new WaitForFixedUpdate(); + } + } + } + + yield return null; + + if (ml && guardTarget && vesselRadarData.locked && (!AIMightDirectFire() || GetLaunchAuthorization(guardTarget, this))) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("Firing on target: " + guardTarget.GetName()); + } + FireCurrentMissile(true); + //StartCoroutine(MissileAwayRoutine(mlauncher)); + } + } + else if (ml.TargetingMode == MissileBase.TargetingModes.Heat) + { + if (vesselRadarData && vesselRadarData.locked) + { + vesselRadarData.UnlockAllTargets(); + vesselRadarData.UnslaveTurrets(); + } + float attemptStartTime = Time.time; + float attemptDuration = Mathf.Max(targetScanInterval * 0.75f, 5f); + SetCargoBays(); + + MissileLauncher mlauncher; + while (ml && Time.time - attemptStartTime < attemptDuration && (!heatTarget.exists || (heatTarget.predictedPosition - guardTarget.transform.position).sqrMagnitude > 40 * 40)) + { + //TODO BDModularGuidance: add turret + //try using missile turret to lock target + mlauncher = ml as MissileLauncher; + if (mlauncher != null) + { + if (mlauncher.missileTurret) + { + mlauncher.missileTurret.slaved = true; + mlauncher.missileTurret.slavedTargetPosition = guardTarget.CoM; + mlauncher.missileTurret.SlavedAim(); + } + } + + yield return new WaitForFixedUpdate(); + } + + //try uncaged IR lock with radar + if (guardTarget && !heatTarget.exists && vesselRadarData && vesselRadarData.radarCount > 0) + { + if (!vesselRadarData.locked || + (vesselRadarData.lockedTargetData.targetData.predictedPosition - + guardTarget.transform.position).sqrMagnitude > 40 * 40) + { + //vesselRadarData.TryLockTarget(guardTarget.transform.position); + vesselRadarData.TryLockTarget(guardTarget); + yield return new WaitForSeconds(Mathf.Min(1, (targetScanInterval * 0.25f))); + } + } + + if (AIMightDirectFire() && ml && heatTarget.exists) + { + float LAstartTime = Time.time; + while (Time.time - LAstartTime < 3 && AIMightDirectFire() && + GetLaunchAuthorization(guardTarget, this)) + { + yield return new WaitForFixedUpdate(); + } + + yield return new WaitForSeconds(0.5f); + } + + //wait for missile turret to point at target + mlauncher = ml as MissileLauncher; + if (mlauncher != null) + { + if (ml && mlauncher.missileTurret && heatTarget.exists) + { + float turretStartTime = attemptStartTime; + while (heatTarget.exists && Time.time - turretStartTime < Mathf.Max(targetScanInterval / 2f, 2)) + { + float angle = Vector3.Angle(mlauncher.missileTurret.finalTransform.forward, mlauncher.missileTurret.slavedTargetPosition - mlauncher.missileTurret.finalTransform.position); + mlauncher.missileTurret.slaved = true; + mlauncher.missileTurret.slavedTargetPosition = MissileGuidance.GetAirToAirFireSolution(mlauncher, heatTarget.predictedPosition, heatTarget.velocity); + mlauncher.missileTurret.SlavedAim(); + + if (angle < 1) + { + turretStartTime -= 3 * Time.fixedDeltaTime; + } + yield return new WaitForFixedUpdate(); + } + } + } + + yield return null; + + if (guardTarget && ml && heatTarget.exists && + (!AIMightDirectFire() || GetLaunchAuthorization(guardTarget, this))) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Firing on target: " + guardTarget.GetName()); + } + + FireCurrentMissile(true); + //StartCoroutine(MissileAwayRoutine(mlauncher)); + } + } + else if (ml.TargetingMode == MissileBase.TargetingModes.Gps) + { + designatedGPSInfo = new GPSTargetInfo(VectorUtils.WorldPositionToGeoCoords(guardTarget.CoM, vessel.mainBody), guardTarget.vesselName.Substring(0, Mathf.Min(12, guardTarget.vesselName.Length))); + + FireCurrentMissile(true); + //if (FireCurrentMissile(true)) + // StartCoroutine(MissileAwayRoutine(ml)); //NEW: try to prevent launching all missile complements at once... + } + else if (ml.TargetingMode == MissileBase.TargetingModes.AntiRad) + { + if (rwr) + { + if (!rwr.rwrEnabled) rwr.EnableRWR(); + if (rwr.rwrEnabled && !rwr.displayRWR) rwr.displayRWR = true; + } + + float attemptStartTime = Time.time; + float attemptDuration = targetScanInterval * 0.75f; + while (Time.time - attemptStartTime < attemptDuration && + (!antiRadTargetAcquired || (antiRadiationTarget - guardTarget.CoM).sqrMagnitude > 20 * 20)) + { + yield return new WaitForFixedUpdate(); + } + + if (SetCargoBays()) + { + yield return new WaitForSeconds(1f); + } + + if (ml && antiRadTargetAcquired && (antiRadiationTarget - guardTarget.CoM).sqrMagnitude < 20 * 20) + { + FireCurrentMissile(true); + //StartCoroutine(MissileAwayRoutine(ml)); + } + } + else if (ml.TargetingMode == MissileBase.TargetingModes.Laser) + { + if (targetingPods.Count > 0) //if targeting pods are available, slew them onto target and lock. + { + List.Enumerator tgp = targetingPods.GetEnumerator(); + while (tgp.MoveNext()) + { + if (tgp.Current == null) continue; + tgp.Current.EnableCamera(); + yield return StartCoroutine(tgp.Current.PointToPositionRoutine(guardTarget.CoM)); + if (tgp.Current.groundStabilized && (tgp.Current.groundTargetPosition - guardTarget.transform.position).sqrMagnitude < 20 * 20) + { + tgp.Current.CoMLock = true; // make the designator continue to paint target + break; + } + } + tgp.Dispose(); + } + + //search for a laser point that corresponds with target vessel + float attemptStartTime = Time.time; + float attemptDuration = targetScanInterval * 0.75f; + while (Time.time - attemptStartTime < attemptDuration && (!laserPointDetected || (foundCam && (foundCam.groundTargetPosition - guardTarget.CoM).sqrMagnitude > 20 * 20))) + { + yield return new WaitForFixedUpdate(); + } + if (SetCargoBays()) + { + yield return new WaitForSeconds(1f); + } + if (ml && laserPointDetected && foundCam && (foundCam.groundTargetPosition - guardTarget.CoM).sqrMagnitude < 20 * 20) + { + FireCurrentMissile(true); + //StartCoroutine(MissileAwayRoutine(ml)); + } + else + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) Debug.Log("[BDArmory]: Laser Target Error"); + } + } + + guardFiringMissile = false; + } + } + + IEnumerator GuardBombRoutine() + { + guardFiringMissile = true; + bool hasSetCargoBays = false; + float bombStartTime = Time.time; + float bombAttemptDuration = Mathf.Max(targetScanInterval, 12f); + float radius = CurrentMissile.GetBlastRadius() * Mathf.Min((1 + (maxMissilesOnTarget / 2f)), 1.5f); + if (CurrentMissile.TargetingMode == MissileBase.TargetingModes.Gps && (designatedGPSInfo.worldPos - guardTarget.CoM).sqrMagnitude > CurrentMissile.GetBlastRadius() * CurrentMissile.GetBlastRadius()) + { + //check database for target first + float twoxsqrRad = 4f * radius * radius; + bool foundTargetInDatabase = false; + List.Enumerator gps = BDATargetManager.GPSTargetList(Team).GetEnumerator(); + while (gps.MoveNext()) + { + if (!((gps.Current.worldPos - guardTarget.CoM).sqrMagnitude < twoxsqrRad)) continue; + designatedGPSInfo = gps.Current; + foundTargetInDatabase = true; + break; + } + gps.Dispose(); + + //no target in gps database, acquire via targeting pod + if (!foundTargetInDatabase) + { + ModuleTargetingCamera tgp = null; + List.Enumerator t = targetingPods.GetEnumerator(); + while (t.MoveNext()) + { + if (t.Current) tgp = t.Current; + } + t.Dispose(); + + if (tgp != null) + { + tgp.EnableCamera(); + yield return StartCoroutine(tgp.PointToPositionRoutine(guardTarget.CoM)); + + if (tgp) + { + if (guardTarget && tgp.groundStabilized && (tgp.groundTargetPosition - guardTarget.transform.position).sqrMagnitude < CurrentMissile.GetBlastRadius() * CurrentMissile.GetBlastRadius()) + { + radius = 500; + designatedGPSInfo = new GPSTargetInfo(tgp.bodyRelativeGTP, "Guard Target"); + bombStartTime = Time.time; + } + else//failed to acquire target via tgp, cancel. + { + tgp.DisableCamera(); + designatedGPSInfo = new GPSTargetInfo(); + guardFiringMissile = false; + yield break; + } + } + else//no gps target and lost tgp, cancel. + { + guardFiringMissile = false; + yield break; + } + } + else //no gps target and no tgp, cancel. + { + guardFiringMissile = false; + yield break; + } + } + } + + bool doProxyCheck = true; + + float prevDist = 2 * radius; + radius = Mathf.Max(radius, 50f); + while (guardTarget && Time.time - bombStartTime < bombAttemptDuration && weaponIndex > 0 && + weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Bomb && missilesAway < maxMissilesOnTarget) + { + float targetDist = Vector3.Distance(bombAimerPosition, guardTarget.CoM); + + if (targetDist < (radius * 20f) && !hasSetCargoBays) + { + SetCargoBays(); + hasSetCargoBays = true; + } + + if (targetDist > radius + || Vector3.Dot(VectorUtils.GetUpDirection(vessel.CoM), vessel.transform.forward) > 0) // roll check + { + if (targetDist < Mathf.Max(radius * 2, 800f) && + Vector3.Dot(guardTarget.CoM - bombAimerPosition, guardTarget.CoM - transform.position) < 0) + { + pilotAI.RequestExtend(guardTarget.CoM); + break; + } + yield return null; + } + else + { + if (doProxyCheck) + { + if (targetDist - prevDist > 0) + { + doProxyCheck = false; + } + else + { + prevDist = targetDist; + } + } + + if (!doProxyCheck) + { + FireCurrentMissile(true); + timeBombReleased = Time.time; + yield return new WaitForSeconds(rippleFire ? 60f / rippleRPM : 0.06f); + if (missilesAway >= maxMissilesOnTarget) + { + yield return new WaitForSeconds(1f); + if (pilotAI) + { + pilotAI.RequestExtend(guardTarget.CoM); + } + } + } + else + { + yield return null; + } + } + } + + designatedGPSInfo = new GPSTargetInfo(); + guardFiringMissile = false; + } + + //IEnumerator MissileAwayRoutine(MissileBase ml) + //{ + // missilesAway++; + + // MissileLauncher launcher = ml as MissileLauncher; + // if (launcher != null) + // { + // float timeStart = Time.time; + // float timeLimit = Mathf.Max(launcher.dropTime + launcher.cruiseTime + launcher.boostTime + 4, 10); + // while (ml) + // { + // if (ml.guidanceActive && Time.time - timeStart < timeLimit) + // { + // yield return null; + // } + // else + // { + // break; + // } + + // } + // } + // else + // { + // while (ml) + // { + // if (ml.MissileState != MissileBase.MissileStates.PostThrust) + // { + // yield return null; + + // } + // else + // { + // break; + // } + // } + // } + + // missilesAway--; + //} + + //IEnumerator BombsAwayRoutine(MissileBase ml) + //{ + // missilesAway++; + // float timeStart = Time.time; + // float timeLimit = 3; + // while (ml) + // { + // if (Time.time - timeStart < timeLimit) + // { + // yield return null; + // } + // else + // { + // break; + // } + // } + // missilesAway--; + //} + + #endregion Enumerators + + #region Audio + + void UpdateVolume() + { + if (audioSource) + { + audioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; + } + if (warningAudioSource) + { + warningAudioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; + } + if (targetingAudioSource) + { + targetingAudioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; + } + } + + void UpdateTargetingAudio() + { + if (BDArmorySetup.GameIsPaused) + { + if (targetingAudioSource.isPlaying) + { + targetingAudioSource.Stop(); + } + return; + } + + if (selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Missile && vessel.isActiveVessel) + { + MissileBase ml = CurrentMissile; + if (ml.TargetingMode == MissileBase.TargetingModes.Heat) + { + if (targetingAudioSource.clip != heatGrowlSound) + { + targetingAudioSource.clip = heatGrowlSound; + } + + if (heatTarget.exists) + { + targetingAudioSource.pitch = Mathf.MoveTowards(targetingAudioSource.pitch, 2, 8 * Time.deltaTime); + } + else + { + targetingAudioSource.pitch = Mathf.MoveTowards(targetingAudioSource.pitch, 1, 8 * Time.deltaTime); + } + + if (!targetingAudioSource.isPlaying) + { + targetingAudioSource.Play(); + } + } + else + { + if (targetingAudioSource.isPlaying) + { + targetingAudioSource.Stop(); + } + } + } + else + { + targetingAudioSource.pitch = 1; + if (targetingAudioSource.isPlaying) + { + targetingAudioSource.Stop(); + } + } + } + + IEnumerator WarningSoundRoutine(float distance, MissileBase ml)//give distance parameter + { + if (distance < this.guardRange) + { + warningSounding = true; + BDArmorySetup.Instance.missileWarningTime = Time.time; + BDArmorySetup.Instance.missileWarning = true; + warningAudioSource.pitch = distance < 800 ? 1.45f : 1f; + warningAudioSource.PlayOneShot(warningSound); + + float waitTime = distance < 800 ? .25f : 1.5f; + + yield return new WaitForSeconds(waitTime); + + if (ml.vessel && CanSeeTarget(ml.vessel)) + { + BDATargetManager.ReportVessel(ml.vessel, this); + } + } + warningSounding = false; + } + + #endregion Audio + + #region CounterMeasure + + public bool isChaffing; + public bool isFlaring; + public bool isECMJamming; + + bool isLegacyCMing; + + int cmCounter; + int cmAmount = 5; + + public void FireAllCountermeasures(int count) + { + StartCoroutine(AllCMRoutine(count)); + } + + public void FireECM() + { + if (!isECMJamming) + { + StartCoroutine(ECMRoutine()); + } + } + + public void FireChaff() + { + if (!isChaffing) + { + StartCoroutine(ChaffRoutine()); + } + } + + IEnumerator ECMRoutine() + { + isECMJamming = true; + //yield return new WaitForSeconds(UnityEngine.Random.Range(0.2f, 1f)); + List.Enumerator ecm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (ecm.MoveNext()) + { + if (ecm.Current == null) continue; + if (ecm.Current.jammerEnabled) yield break; + ecm.Current.EnableJammer(); + } + ecm.Dispose(); + yield return new WaitForSeconds(10.0f); + isECMJamming = false; + + List.Enumerator ecm1 = vessel.FindPartModulesImplementing().GetEnumerator(); + while (ecm1.MoveNext()) + { + if (ecm1.Current == null) continue; + ecm1.Current.DisableJammer(); + } + ecm1.Dispose(); + } + + IEnumerator ChaffRoutine() + { + isChaffing = true; + yield return new WaitForSeconds(UnityEngine.Random.Range(0.2f, 1f)); + List.Enumerator cm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (cm.MoveNext()) + { + if (cm.Current == null) continue; + if (cm.Current.cmType == CMDropper.CountermeasureTypes.Chaff) + { + cm.Current.DropCM(); + } + } + cm.Dispose(); + + yield return new WaitForSeconds(0.6f); + + isChaffing = false; + } + + IEnumerator FlareRoutine(float time) + { + if (isFlaring) yield break; + time = Mathf.Clamp(time, 2, 8); + isFlaring = true; + yield return new WaitForSeconds(UnityEngine.Random.Range(0f, 1f)); + float flareStartTime = Time.time; + while (Time.time - flareStartTime < time) + { + List.Enumerator cm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (cm.MoveNext()) + { + if (cm.Current == null) continue; + if (cm.Current.cmType == CMDropper.CountermeasureTypes.Flare) + { + cm.Current.DropCM(); + } + } + cm.Dispose(); + yield return new WaitForSeconds(0.6f); + } + isFlaring = false; + } + + IEnumerator AllCMRoutine(int count) + { + for (int i = 0; i < count; i++) + { + List.Enumerator cm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (cm.MoveNext()) + { + if (cm.Current == null) continue; + if ((cm.Current.cmType == CMDropper.CountermeasureTypes.Flare && !isFlaring) + || (cm.Current.cmType == CMDropper.CountermeasureTypes.Chaff && !isChaffing) + || (cm.Current.cmType == CMDropper.CountermeasureTypes.Smoke)) + { + cm.Current.DropCM(); + } + } + cm.Dispose(); + isFlaring = true; + isChaffing = true; + yield return new WaitForSeconds(1f); + } + isFlaring = false; + isChaffing = false; + } + + IEnumerator LegacyCMRoutine() + { + isLegacyCMing = true; + yield return new WaitForSeconds(UnityEngine.Random.Range(.2f, 1f)); + if (incomingMissileDistance < 2500) + { + cmAmount = Mathf.RoundToInt((2500 - incomingMissileDistance) / 400); + List.Enumerator cm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (cm.MoveNext()) + { + if (cm.Current == null) continue; + cm.Current.DropCM(); + } + cm.Dispose(); + cmCounter++; + if (cmCounter < cmAmount) + { + yield return new WaitForSeconds(0.15f); + } + else + { + cmCounter = 0; + yield return new WaitForSeconds(UnityEngine.Random.Range(.5f, 1f)); + } + } + isLegacyCMing = false; + } + + public void MissileWarning(float distance, MissileBase ml)//take distance parameter + { + if (vessel.isActiveVessel && !warningSounding) + { + StartCoroutine(WarningSoundRoutine(distance, ml)); + } + + missileIsIncoming = true; + incomingMissileDistance = distance; + } + + #endregion CounterMeasure + + #region Fire + + bool FireCurrentMissile(bool checkClearance) + { + MissileBase missile = CurrentMissile; + if (missile == null) return false; + + if (missile is MissileBase) + { + MissileBase ml = missile; + if (checkClearance && (!CheckBombClearance(ml) || (ml is MissileLauncher && ((MissileLauncher)ml).rotaryRail && !((MissileLauncher)ml).rotaryRail.readyMissile == ml))) + { + List.Enumerator otherMissile = vessel.FindPartModulesImplementing().GetEnumerator(); + while (otherMissile.MoveNext()) + { + if (otherMissile.Current == null) continue; + if (otherMissile.Current == ml || otherMissile.Current.GetShortName() != ml.GetShortName() || + !CheckBombClearance(otherMissile.Current)) continue; + CurrentMissile = otherMissile.Current; + selectedWeapon = otherMissile.Current; + FireCurrentMissile(false); + return true; + } + otherMissile.Dispose(); + CurrentMissile = ml; + selectedWeapon = ml; + return false; + } + + if (ml is MissileLauncher && ((MissileLauncher)ml).missileTurret) + { + ((MissileLauncher)ml).missileTurret.FireMissile(((MissileLauncher)ml)); + } + else if (ml is MissileLauncher && ((MissileLauncher)ml).rotaryRail) + { + ((MissileLauncher)ml).rotaryRail.FireMissile(((MissileLauncher)ml)); + } + else + { + SendTargetDataToMissile(ml); + ml.FireMissile(); + } + + if (guardMode) + { + if (ml.GetWeaponClass() == WeaponClasses.Bomb) + { + //StartCoroutine(BombsAwayRoutine(ml)); + } + } + else + { + if (vesselRadarData && vesselRadarData.autoCycleLockOnFire) + { + vesselRadarData.CycleActiveLock(); + } + } + } + else + { + SendTargetDataToMissile(missile); + missile.FireMissile(); + } + + UpdateList(); + return true; + } + + void FireMissile() + { + if (weaponIndex == 0) + { + return; + } + + if (selectedWeapon == null) + { + return; + } + + if (selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || + selectedWeapon.GetWeaponClass() == WeaponClasses.SLW || + selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) + { + FireCurrentMissile(true); + } + else if (selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) + { + if (!currentRocket || currentRocket.part.name != selectedWeapon.GetPart().name) + { + FindNextRocket(null); + } + + if (currentRocket) + { + currentRocket.FireRocket(); + FindNextRocket(currentRocket); + } + } + + UpdateList(); + } + + #endregion Fire + + #region Weapon Info + + void DisplaySelectedWeaponMessage() + { + if (BDArmorySetup.GAME_UI_ENABLED && vessel == FlightGlobals.ActiveVessel) + { + ScreenMessages.RemoveMessage(selectionMessage); + selectionMessage.textInstance = null; + + selectionText = "Selected Weapon: " + (GetWeaponName(weaponArray[weaponIndex])).ToString(); + selectionMessage.message = selectionText; + selectionMessage.style = ScreenMessageStyle.UPPER_CENTER; + + ScreenMessages.PostScreenMessage(selectionMessage); + } + } + + string GetWeaponName(IBDWeapon weapon) + { + if (weapon == null) + { + return "None"; + } + else + { + return weapon.GetShortName(); + } + } + + public void UpdateList() + { + weaponTypes.Clear(); + // extension for feature_engagementenvelope: also clear engagement specific weapon lists + weaponTypesAir.Clear(); + weaponTypesMissile.Clear(); + weaponTypesGround.Clear(); + weaponTypesSLW.Clear(); + + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + string weaponName = weapon.Current.GetShortName(); + bool alreadyAdded = false; + List.Enumerator weap = weaponTypes.GetEnumerator(); + while (weap.MoveNext()) + { + if (weap.Current == null) continue; + if (weap.Current.GetShortName() == weaponName) + { + alreadyAdded = true; + //break; + } + } + weap.Dispose(); + + //dont add empty rocket pods + if (weapon.Current.GetWeaponClass() == WeaponClasses.Rocket && + weapon.Current.GetPart().FindModuleImplementing().GetRocketResource().amount < 1 + && !BDArmorySettings.INFINITE_AMMO) + { + continue; + } + + if (!alreadyAdded) + { + weaponTypes.Add(weapon.Current); + } + + EngageableWeapon engageableWeapon = weapon.Current as EngageableWeapon; + + if (engageableWeapon != null) + { + if (engageableWeapon.GetEngageAirTargets()) weaponTypesAir.Add(weapon.Current); + if (engageableWeapon.GetEngageMissileTargets()) weaponTypesMissile.Add(weapon.Current); + if (engageableWeapon.GetEngageGroundTargets()) weaponTypesGround.Add(weapon.Current); + if (engageableWeapon.GetEngageSLWTargets()) weaponTypesSLW.Add(weapon.Current); + } + else + { + weaponTypesAir.Add(weapon.Current); + weaponTypesMissile.Add(weapon.Current); + weaponTypesGround.Add(weapon.Current); + weaponTypesSLW.Add(weapon.Current); + } + + if (weapon.Current.GetWeaponClass() == WeaponClasses.Bomb || + weapon.Current.GetWeaponClass() == WeaponClasses.Missile || + weapon.Current.GetWeaponClass() == WeaponClasses.SLW) + { + weapon.Current.GetPart().FindModuleImplementing().GetMissileCount(); // #191, Do it this way so the GetMissileCount only updates when missile fired + } + } + weapon.Dispose(); + + //weaponTypes.Sort(); + weaponTypes = weaponTypes.OrderBy(w => w.GetShortName()).ToList(); + + List tempList = new List { null }; + tempList.AddRange(weaponTypes); + + weaponArray = tempList.ToArray(); + + if (weaponIndex >= weaponArray.Length) + { + hasSingleFired = true; + triggerTimer = 0; + } + PrepareWeapons(); + } + + private void PrepareWeapons() + { + if (vessel == null) return; + + weaponIndex = Mathf.Clamp(weaponIndex, 0, weaponArray.Length - 1); + + if (selectedWeapon == null || selectedWeapon.GetPart() == null || (selectedWeapon.GetPart().vessel != null && selectedWeapon.GetPart().vessel != vessel) || + GetWeaponName(selectedWeapon) != GetWeaponName(weaponArray[weaponIndex])) + { + selectedWeapon = weaponArray[weaponIndex]; + + if (vessel.isActiveVessel && Time.time - startTime > 1) + { + hasSingleFired = true; + } + + if (vessel.isActiveVessel && weaponIndex != 0) + { + DisplaySelectedWeaponMessage(); + } + } + + if (weaponIndex == 0) + { + selectedWeapon = null; + hasSingleFired = true; + } + + MissileBase aMl = GetAsymMissile(); + if (aMl) + { + selectedWeapon = aMl; + } + + MissileBase rMl = GetRotaryReadyMissile(); + if (rMl) + { + selectedWeapon = rMl; + } + + UpdateSelectedWeaponState(); + } + + private void UpdateSelectedWeaponState() + { + if (vessel == null) return; + + MissileBase aMl = GetAsymMissile(); + if (aMl) + { + CurrentMissile = aMl; + } + + MissileBase rMl = GetRotaryReadyMissile(); + if (rMl) + { + CurrentMissile = rMl; + } + + if (selectedWeapon != null && (selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb || selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || selectedWeapon.GetWeaponClass() == WeaponClasses.SLW)) + { + //Debug.Log("[BDArmory]: =====selected weapon: " + selectedWeapon.GetPart().name); + if (!CurrentMissile || CurrentMissile.part.name != selectedWeapon.GetPart().name) + { + CurrentMissile = selectedWeapon.GetPart().FindModuleImplementing(); + } + } + else + { + CurrentMissile = null; + } + + //selectedWeapon = weaponArray[weaponIndex]; + + //bomb stuff + if (selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) + { + bombPart = selectedWeapon.GetPart(); + } + else + { + bombPart = null; + } + + //gun ripple stuff + if (selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun && + currentGun.roundsPerMinute < 1500) + { + float counter = 0; // Used to get a count of the ripple weapons. a float version of rippleGunCount. + gunRippleIndex = 0; + // This value will be incremented as we set the ripple weapons + rippleGunCount = 0; + float weaponRpm = 0; // used to set the rippleGunRPM + + // JDK: this looks like it can be greatly simplified... + + #region Old Code (for reference. remove when satisfied new code works as expected. + + //List tempListModuleWeapon = vessel.FindPartModulesImplementing(); + //foreach (ModuleWeapon weapon in tempListModuleWeapon) + //{ + // if (selectedWeapon.GetShortName() == weapon.GetShortName()) + // { + // weapon.rippleIndex = Mathf.RoundToInt(counter); + // weaponRPM = weapon.roundsPerMinute; + // ++counter; + // rippleGunCount++; + // } + //} + //gunRippleRpm = weaponRPM * counter; + //float timeDelayPerGun = 60f / (weaponRPM * counter); + ////number of seconds between each gun firing; will reduce with increasing RPM or number of guns + //foreach (ModuleWeapon weapon in tempListModuleWeapon) + //{ + // if (selectedWeapon.GetShortName() == weapon.GetShortName()) + // { + // weapon.initialFireDelay = timeDelayPerGun; //set the time delay for moving to next index + // } + //} + + //RippleOption ro; //ripplesetup and stuff + //if (rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) + //{ + // ro = rippleDictionary[selectedWeapon.GetShortName()]; + //} + //else + //{ + // ro = new RippleOption(currentGun.useRippleFire, 650); //take from gun's persistant value + // rippleDictionary.Add(selectedWeapon.GetShortName(), ro); + //} + + //foreach (ModuleWeapon w in vessel.FindPartModulesImplementing()) + //{ + // if (w.GetShortName() == selectedWeapon.GetShortName()) + // w.useRippleFire = ro.rippleFire; + //} + + #endregion Old Code (for reference. remove when satisfied new code works as expected. + + // TODO: JDK verify new code works as expected. + // New code, simplified. + + //First lest set the Ripple Option. Doing it first eliminates a loop. + RippleOption ro; //ripplesetup and stuff + if (rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) + { + ro = rippleDictionary[selectedWeapon.GetShortName()]; + } + else + { + ro = new RippleOption(currentGun.useRippleFire, 650); //take from gun's persistant value + rippleDictionary.Add(selectedWeapon.GetShortName(), ro); + } + + //Get ripple weapon count, so we don't have to enumerate the whole list again. + List rippleWeapons = new List(); + List.Enumerator weapCnt = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapCnt.MoveNext()) + { + if (weapCnt.Current == null) continue; + if (selectedWeapon.GetShortName() != weapCnt.Current.GetShortName()) continue; + weaponRpm = weapCnt.Current.roundsPerMinute; + rippleWeapons.Add(weapCnt.Current); + counter += weaponRpm; // grab sum of weapons rpm + } + weapCnt.Dispose(); + + gunRippleRpm = counter; + //number of seconds between each gun firing; will reduce with increasing RPM or number of guns + float timeDelayPerGun = 60f / gunRippleRpm; // rpm*counter will return the square of rpm now + // Now lets act on the filtered list. + List.Enumerator weapon = rippleWeapons.GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + // set the weapon ripple index just before we increment rippleGunCount. + weapon.Current.rippleIndex = rippleGunCount; + //set the time delay for moving to next index + weapon.Current.initialFireDelay = timeDelayPerGun; + weapon.Current.useRippleFire = ro.rippleFire; + rippleGunCount++; + } + weapon.Dispose(); + } + + //rocket + FindNextRocket(null); + + ToggleTurret(); + SetMissileTurrets(); + SetRocketTurrets(); + SetRotaryRails(); + } + + private bool SetCargoBays() + { + if (!guardMode) return false; + bool openingBays = false; + + if (weaponIndex > 0 && CurrentMissile && guardTarget && Vector3.Dot(guardTarget.transform.position - CurrentMissile.transform.position, CurrentMissile.GetForwardTransform()) > 0) + { + if (CurrentMissile.part.ShieldedFromAirstream) + { + List.Enumerator ml = vessel.FindPartModulesImplementing().GetEnumerator(); + while (ml.MoveNext()) + { + if (ml.Current == null) continue; + if (ml.Current.part.ShieldedFromAirstream) ml.Current.inCargoBay = true; + } + ml.Dispose(); + } + + if (CurrentMissile.inCargoBay) + { + List.Enumerator bay = vessel.FindPartModulesImplementing().GetEnumerator(); + while (bay.MoveNext()) + { + if (bay.Current == null) continue; + if (CurrentMissile.part.airstreamShields.Contains(bay.Current)) + { + ModuleAnimateGeneric anim = bay.Current.part.Modules.GetModule(bay.Current.DeployModuleIndex) as ModuleAnimateGeneric; + if (anim == null) continue; + + string toggleOption = anim.Events["Toggle"].guiName; + if (toggleOption == "Open") + { + if (anim) + { + anim.Toggle(); + openingBays = true; + } + } + } + else + { + ModuleAnimateGeneric anim = + bay.Current.part.Modules.GetModule(bay.Current.DeployModuleIndex) as ModuleAnimateGeneric; + if (anim == null) continue; + + string toggleOption = anim.Events["Toggle"].guiName; + if (toggleOption == "Close") + { + if (anim) + { + anim.Toggle(); + } + } + } + } + bay.Dispose(); + } + else + { + List.Enumerator bay = vessel.FindPartModulesImplementing().GetEnumerator(); + while (bay.MoveNext()) + { + if (bay.Current == null) continue; + ModuleAnimateGeneric anim = + bay.Current.part.Modules.GetModule(bay.Current.DeployModuleIndex) as ModuleAnimateGeneric; + if (anim == null) continue; + + string toggleOption = anim.Events["Toggle"].guiName; + if (toggleOption == "Close") + { + if (anim) + { + anim.Toggle(); + } + } + } + bay.Dispose(); + } + } + else + { + List.Enumerator bay = vessel.FindPartModulesImplementing().GetEnumerator(); + while (bay.MoveNext()) + { + if (bay.Current == null) continue; + ModuleAnimateGeneric anim = bay.Current.part.Modules.GetModule(bay.Current.DeployModuleIndex) as ModuleAnimateGeneric; + if (anim == null) continue; + + string toggleOption = anim.Events["Toggle"].guiName; + if (toggleOption == "Close") + { + if (anim) + { + anim.Toggle(); + } + } + } + bay.Dispose(); + } + + return openingBays; + } + + void SetRotaryRails() + { + if (weaponIndex == 0) return; + + if (selectedWeapon == null) return; + + if ( + !(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || + selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb || + selectedWeapon.GetWeaponClass() == WeaponClasses.SLW)) return; + + if (!CurrentMissile) return; + + //TODO BDModularGuidance: Rotatory Rail? + MissileLauncher cm = CurrentMissile as MissileLauncher; + if (cm == null) return; + List.Enumerator rotRail = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rotRail.MoveNext()) + { + if (rotRail.Current == null) continue; + if (rotRail.Current.missileCount == 0) + { + //Debug.Log("SetRotaryRails(): rail has no missiles"); + continue; + } + + //Debug.Log("[BDArmory]: SetRotaryRails(): rotRail.Current.readyToFire: " + rotRail.Current.readyToFire + ", rotRail.Current.readyMissile: " + ((rotRail.Current.readyMissile != null) ? rotRail.Current.readyMissile.part.name : "null") + ", rotRail.Current.nextMissile: " + ((rotRail.Current.nextMissile != null) ? rotRail.Current.nextMissile.part.name : "null")); + + //Debug.Log("[BDArmory]: current missile: " + cm.part.name); + + if (rotRail.Current.readyToFire) + { + if (!rotRail.Current.readyMissile) + { + rotRail.Current.RotateToMissile(cm); + return; + } + + if (rotRail.Current.readyMissile.part.name != cm.part.name) + { + rotRail.Current.RotateToMissile(cm); + } + } + else + { + if (!rotRail.Current.nextMissile) + { + rotRail.Current.RotateToMissile(cm); + } + else if (rotRail.Current.nextMissile.part.name != cm.part.name) + { + rotRail.Current.RotateToMissile(cm); + } + } + } + rotRail.Dispose(); + } + + void SetMissileTurrets() + { + MissileLauncher cm = CurrentMissile as MissileLauncher; + List.Enumerator mt = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mt.MoveNext()) + { + if (mt.Current == null) continue; + if (weaponIndex > 0 && cm && mt.Current.ContainsMissileOfType(cm) && (!mt.Current.activeMissileOnly || cm.missileTurret == mt.Current)) + { + mt.Current.EnableTurret(); + } + else + { + mt.Current.DisableTurret(); + } + } + mt.Dispose(); + } + + void SetRocketTurrets() + { + RocketLauncher currentTurret = null; + if (selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) + { + RocketLauncher srl = selectedWeapon.GetPart().FindModuleImplementing(); + if (srl && srl.turret) + { + currentTurret = srl; + } + } + + List.Enumerator rl = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rl.MoveNext()) + { + if (rl.Current == null) continue; + rl.Current.weaponManager = this; + if (rl.Current.turret) + { + if (currentTurret && rl.Current.part.name == currentTurret.part.name) + { + rl.Current.EnableTurret(); + } + else + { + rl.Current.DisableTurret(); + } + } + } + rl.Dispose(); + } + + void FindNextRocket(RocketLauncher lastFired) + { + if (weaponIndex > 0 && selectedWeapon?.GetWeaponClass() == WeaponClasses.Rocket) + { + disabledRocketAimers = false; + + //first check sym of last fired + if (lastFired && lastFired.part.name == selectedWeapon.GetPart().name) + { + List.Enumerator pSym = lastFired.part.symmetryCounterparts.GetEnumerator(); + while (pSym.MoveNext()) + { + if (pSym.Current == null) continue; + bool hasRocket = false; + RocketLauncher rl = pSym.Current.FindModuleImplementing(); + IEnumerator r = rl.part.Resources.GetEnumerator(); + while (r.MoveNext()) + { + if (r.Current == null) continue; + if ((r.Current.resourceName != rl.rocketType || !(r.Current.amount > 0)) + && !BDArmorySettings.INFINITE_AMMO) continue; + hasRocket = true; + break; + } + r.Dispose(); + + if (!hasRocket) continue; + if (currentRocket) currentRocket.drawAimer = false; + + rl.drawAimer = true; + currentRocket = rl; + selectedWeapon = currentRocket; + return; + } + } + + if (!lastFired && currentRocket && currentRocket.part.name == selectedWeapon.GetPart().name) + { + currentRocket.drawAimer = true; + selectedWeapon = currentRocket; + return; + } + + //then check for other rocket + bool foundRocket = false; + List.Enumerator orl = vessel.FindPartModulesImplementing().GetEnumerator(); + while (orl.MoveNext()) + { + if (orl.Current == null) continue; + if (!foundRocket && orl.Current.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) + { + bool hasRocket = false; + IEnumerator r = orl.Current.part.Resources.GetEnumerator(); + while (r.MoveNext()) + { + if (r.Current == null) continue; + if (r.Current.amount > 0 || BDArmorySettings.INFINITE_AMMO) hasRocket = true; + else orl.Current.drawAimer = false; + } + r.Dispose(); + + if (!hasRocket) continue; + if (currentRocket != null) currentRocket.drawAimer = false; + orl.Current.drawAimer = true; + currentRocket = orl.Current; + selectedWeapon = currentRocket; + //return; + foundRocket = true; + } + else + { + orl.Current.drawAimer = false; + } + } + orl.Dispose(); + } + //not using a rocket, disable reticles. + else if (!disabledRocketAimers) + { + List.Enumerator rl = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rl.MoveNext()) + { + if (rl.Current == null) continue; + rl.Current.drawAimer = false; + currentRocket = null; + } + rl.Dispose(); + disabledRocketAimers = true; + } + } + + public void CycleWeapon(bool forward) + { + if (forward) weaponIndex++; + else weaponIndex--; + weaponIndex = (int)Mathf.Repeat(weaponIndex, weaponArray.Length); + + hasSingleFired = true; + triggerTimer = 0; + + UpdateList(); + + DisplaySelectedWeaponMessage(); + + if (vessel.isActiveVessel && !guardMode) + { + audioSource.PlayOneShot(clickSound); + } + } + + public void CycleWeapon(int index) + { + if (index >= weaponArray.Length) + { + index = 0; + } + weaponIndex = index; + + UpdateList(); + + if (vessel.isActiveVessel && !guardMode) + { + audioSource.PlayOneShot(clickSound); + + DisplaySelectedWeaponMessage(); + } + } + + public Part FindSym(Part p) + { + List.Enumerator pSym = p.symmetryCounterparts.GetEnumerator(); + while (pSym.MoveNext()) + { + if (pSym.Current == null) continue; + if (pSym.Current != p && pSym.Current.vessel == vessel) + { + return pSym.Current; + } + } + pSym.Dispose(); + + return null; + } + + private MissileBase GetAsymMissile() + { + if (weaponIndex == 0) return null; + if (weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Bomb || + weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Missile || + weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.SLW) + { + MissileBase firstMl = null; + List.Enumerator ml = vessel.FindPartModulesImplementing().GetEnumerator(); + while (ml.MoveNext()) + { + if (ml.Current == null) continue; + MissileLauncher launcher = ml.Current as MissileLauncher; + if (launcher != null) + { + if (launcher.part.name != weaponArray[weaponIndex].GetPart()?.name) continue; + } + else + { + BDModularGuidance guidance = ml.Current as BDModularGuidance; + if (guidance != null) + { //We have set of parts not only a part + if (guidance.GetShortName() != weaponArray[weaponIndex]?.GetShortName()) continue; + } + } + if (firstMl == null) firstMl = ml.Current; + + if (!FindSym(ml.Current.part)) + { + return ml.Current; + } + } + ml.Dispose(); + return firstMl; + } + return null; + } + + private MissileBase GetRotaryReadyMissile() + { + if (weaponIndex == 0) return null; + if (weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Bomb || + weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Missile || + weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.SLW) + { + //TODO BDModularGuidance: Implemente rotaryRail support + MissileLauncher missile = CurrentMissile as MissileLauncher; + if (missile == null) return null; + if (missile && missile.part.name == weaponArray[weaponIndex].GetPart().name) + { + if (!missile.rotaryRail) + { + return missile; + } + if (missile.rotaryRail.readyToFire && missile.rotaryRail.readyMissile == CurrentMissile) + { + return missile; + } + } + List.Enumerator ml = vessel.FindPartModulesImplementing().GetEnumerator(); + while (ml.MoveNext()) + { + if (ml.Current == null) continue; + if (ml.Current.part.name != weaponArray[weaponIndex].GetPart().name) continue; + + if (!ml.Current.rotaryRail) + { + return ml.Current; + } + if (ml.Current.rotaryRail.readyToFire && ml.Current.rotaryRail.readyMissile.part.name == weaponArray[weaponIndex].GetPart().name) + { + return ml.Current.rotaryRail.readyMissile; + } + } + ml.Dispose(); + return null; + } + return null; + } + + bool CheckBombClearance(MissileBase ml) + { + if (!BDArmorySettings.BOMB_CLEARANCE_CHECK) return true; + + if (ml.part.ShieldedFromAirstream) + { + return false; + } + + //TODO BDModularGuidance: Bombs and turrents + MissileLauncher launcher = ml as MissileLauncher; + if (launcher != null) + { + if (launcher.rotaryRail && launcher.rotaryRail.readyMissile != ml) + { + return false; + } + + if (launcher.missileTurret && !launcher.missileTurret.turretEnabled) + { + return false; + } + + if (ml.dropTime > 0.3f) + { + //debug lines + LineRenderer lr = null; + if (BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) + { + lr = GetComponent(); + if (!lr) + { + lr = gameObject.AddComponent(); + } + lr.enabled = true; + lr.startWidth = .1f; + lr.endWidth = .1f; + } + else + { + if (gameObject.GetComponent()) + { + gameObject.GetComponent().enabled = false; + } + } + + float radius = launcher.decoupleForward ? launcher.ClearanceRadius : launcher.ClearanceLength; + float time = Mathf.Min(ml.dropTime, 2f); + Vector3 direction = ((launcher.decoupleForward + ? ml.MissileReferenceTransform.transform.forward + : -ml.MissileReferenceTransform.transform.up) * launcher.decoupleSpeed * time) + + ((FlightGlobals.getGeeForceAtPosition(transform.position) - vessel.acceleration) * + 0.5f * time * time); + Vector3 crossAxis = Vector3.Cross(direction, ml.MissileReferenceTransform.transform.right).normalized; + + float rayDistance; + if (launcher.thrust == 0 || launcher.cruiseThrust == 0) + { + rayDistance = 8; + } + else + { + //distance till engine starts based on grav accel and vessel accel + rayDistance = direction.magnitude; + } + + Ray[] rays = + { + new Ray(ml.MissileReferenceTransform.position - (radius*crossAxis), direction), + new Ray(ml.MissileReferenceTransform.position + (radius*crossAxis), direction), + new Ray(ml.MissileReferenceTransform.position, direction) + }; + + if (lr) + { + lr.useWorldSpace = false; + lr.positionCount = 4; + lr.SetPosition(0, transform.InverseTransformPoint(rays[0].origin)); + lr.SetPosition(1, transform.InverseTransformPoint(rays[0].GetPoint(rayDistance))); + lr.SetPosition(2, transform.InverseTransformPoint(rays[1].GetPoint(rayDistance))); + lr.SetPosition(3, transform.InverseTransformPoint(rays[1].origin)); + } + + IEnumerator rt = rays.AsEnumerable().GetEnumerator(); + while (rt.MoveNext()) + { + RaycastHit[] hits = Physics.RaycastAll(rt.Current, rayDistance, 557057); + IEnumerator t1 = hits.AsEnumerable().GetEnumerator(); + while (t1.MoveNext()) + { + Part p = t1.Current.collider.GetComponentInParent(); + + if ((p == null || p == ml.part) && p != null) continue; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: RAYCAST HIT, clearance is FALSE! part=" + p?.name + ", collider=" + p?.collider); + return false; + } + t1.Dispose(); + } + rt.Dispose(); + return true; + } + + //forward check for no-drop missiles + RaycastHit[] hitparts = Physics.RaycastAll(new Ray(ml.MissileReferenceTransform.position, ml.GetForwardTransform()), 50, 557057); + IEnumerator t = hitparts.AsEnumerable().GetEnumerator(); + while (t.MoveNext()) + { + Part p = t.Current.collider.GetComponentInParent(); + if ((p == null || p == ml.part) && p != null) continue; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: RAYCAST HIT, clearance is FALSE! part=" + p?.name + ", collider=" + p?.collider); + return false; + } + t.Dispose(); + } + return true; + } + + void RefreshModules() + { + radars = vessel.FindPartModulesImplementing(); + + List.Enumerator rad = radars.GetEnumerator(); + while (rad.MoveNext()) + { + if (rad.Current == null) continue; + rad.Current.EnsureVesselRadarData(); + if (rad.Current.radarEnabled) rad.Current.EnableRadar(); + } + rad.Dispose(); + + jammers = vessel.FindPartModulesImplementing(); + targetingPods = vessel.FindPartModulesImplementing(); + wmModules = vessel.FindPartModulesImplementing(); + } + + #endregion Weapon Info +/* + #region Weapon Choice + // Unnecessary. Bool Smart Pick now handles Antirad selection + bool TryPickAntiRad(TargetInfo target) + { + CycleWeapon(0); //go to start of array + while (true) + { + CycleWeapon(true); + if (selectedWeapon == null) return false; + if (selectedWeapon.GetWeaponClass() != WeaponClasses.Missile) continue; + List.Enumerator ml = selectedWeapon.GetPart().FindModulesImplementing().GetEnumerator(); + while (ml.MoveNext()) + { + if (ml.Current == null) continue; + if (ml.Current.TargetingMode == MissileBase.TargetingModes.AntiRad) + { + return true; + } + break; + } + ml.Dispose(); + //return; + } + } + + #endregion Weapon Choice +*/ + #region Targeting + + #region Smart Targeting + + void SmartFindTarget() + { + List targetsTried = new List(); + + if (overrideTarget) //begin by checking the override target, since that takes priority + { + targetsTried.Add(overrideTarget); + SetTarget(overrideTarget); + if (SmartPickWeapon_EngagementEnvelope(overrideTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging an override target with " + selectedWeapon); + } + overrideTimer = 15f; + return; + } + else if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging an override target with failed to engage its override target!"); + } + } + overrideTarget = null; //null the override target if it cannot be used + + //if AIRBORNE, try to engage airborne target first + if (!vessel.LandedOrSplashed && !targetMissiles) + { + if (pilotAI && pilotAI.IsExtending) + { + TargetInfo potentialAirTarget = BDATargetManager.GetAirToAirTargetAbortExtend(this, 1500, 0.2f); + if (potentialAirTarget) + { + targetsTried.Add(potentialAirTarget); + SetTarget(potentialAirTarget); + if (SmartPickWeapon_EngagementEnvelope(potentialAirTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is aborting extend and engaging an incoming airborne target with " + selectedWeapon); + } + return; + } + } + } + else + { + TargetInfo potentialAirTarget = BDATargetManager.GetAirToAirTarget(this); + if (potentialAirTarget) + { + targetsTried.Add(potentialAirTarget); + SetTarget(potentialAirTarget); + if (SmartPickWeapon_EngagementEnvelope(potentialAirTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging an airborne target with " + selectedWeapon); + } + return; + } + } + } + } + + TargetInfo potentialTarget = null; + //=========HIGH PRIORITY MISSILES============= + //first engage any missiles targeting this vessel + potentialTarget = BDATargetManager.GetMissileTarget(this, true); + if (potentialTarget) + { + targetsTried.Add(potentialTarget); + SetTarget(potentialTarget); + if (SmartPickWeapon_EngagementEnvelope(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging incoming missile with " + selectedWeapon); + } + return; + } + } + + //then engage any missiles that are not engaged + potentialTarget = BDATargetManager.GetUnengagedMissileTarget(this); + if (potentialTarget) + { + targetsTried.Add(potentialTarget); + SetTarget(potentialTarget); + if (SmartPickWeapon_EngagementEnvelope(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging unengaged missile with " + selectedWeapon); + } + return; + } + } + + //=========END HIGH PRIORITY MISSILES============= + + //============VESSEL THREATS============ + if (!targetMissiles) + { + //then try to engage enemies with least friendlies already engaging them + potentialTarget = BDATargetManager.GetLeastEngagedTarget(this); + if (potentialTarget) + { + targetsTried.Add(potentialTarget); + SetTarget(potentialTarget); + /* + if (CrossCheckWithRWR(potentialTarget) && TryPickAntiRad(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging the least engaged radar target with " + + selectedWeapon.GetShortName()); + } + return; + } + */ + if (SmartPickWeapon_EngagementEnvelope(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging the least engaged target with " + + selectedWeapon.GetShortName()); + } + return; + } + } + + //then engage the closest enemy + potentialTarget = BDATargetManager.GetClosestTarget(this); + if (potentialTarget) + { + targetsTried.Add(potentialTarget); + SetTarget(potentialTarget); + /* + if (CrossCheckWithRWR(potentialTarget) && TryPickAntiRad(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging the closest radar target with " + + selectedWeapon.GetShortName()); + } + return; + } + */ + if (SmartPickWeapon_EngagementEnvelope(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging the closest target with " + + selectedWeapon.GetShortName()); + } + return; + } + } + } + //============END VESSEL THREATS============ + + //============LOW PRIORITY MISSILES========= + //try to engage least engaged hostile missiles first + potentialTarget = BDATargetManager.GetMissileTarget(this); + if (potentialTarget) + { + targetsTried.Add(potentialTarget); + SetTarget(potentialTarget); + if (SmartPickWeapon_EngagementEnvelope(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]:" + vessel.vesselName + " is engaging a missile with " + selectedWeapon.GetShortName()); + } + return; + } + } + + //then try to engage closest hostile missile + potentialTarget = BDATargetManager.GetClosestMissileTarget(this); + if (potentialTarget) + { + targetsTried.Add(potentialTarget); + SetTarget(potentialTarget); + if (SmartPickWeapon_EngagementEnvelope(potentialTarget)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]:" + vessel.vesselName + " is engaging a missile with " + selectedWeapon.GetShortName()); + } + return; + } + } + //==========END LOW PRIORITY MISSILES============= + + if (targetMissiles) //NO MISSILES BEYOND THIS POINT// + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]:" + vessel.vesselName + " is disengaging - no valid weapons"); + } + CycleWeapon(0); + SetTarget(null); + return; + } + + //if nothing works, get all remaining targets and try weapons against them + List.Enumerator finalTargets = BDATargetManager.GetAllTargetsExcluding(targetsTried, this).GetEnumerator(); + while (finalTargets.MoveNext()) + { + if (finalTargets.Current == null) continue; + SetTarget(finalTargets.Current); + if (!SmartPickWeapon_EngagementEnvelope(finalTargets.Current)) continue; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is engaging a final target with " + + selectedWeapon.GetShortName()); + } + return; + } + + //no valid targets found + if (potentialTarget == null || selectedWeapon == null) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + vessel.vesselName + " is disengaging - no valid weapons - no valid targets"); + } + CycleWeapon(0); + SetTarget(null); + if (vesselRadarData && vesselRadarData.locked) + { + vesselRadarData.UnlockAllTargets(); + } + return; + } + + Debug.Log("[BDArmory]: Unhandled target case"); + } + + // extension for feature_engagementenvelope: new smartpickweapon method + bool SmartPickWeapon_EngagementEnvelope(TargetInfo target) + { + // Part 1: Guard conditions (when not to pick a weapon) + // ------ + if (!target) + return false; + + if (AI != null && AI.pilotEnabled && !AI.CanEngage()) + return false; + + // Part 2: check weapons against individual target types + // ------ + + float distance = Vector3.Distance(transform.position + vessel.Velocity(), target.position + target.velocity); + IBDWeapon targetWeapon = null; + float targetWeaponRPM = 0; + float targetWeaponTDPS = 0; + float targetWeaponImpact = 0; + float targetLaserDamage = 0; + float targetYield = 0; + float targetRocketPower = 0; + + if (target.isMissile) + { + // iterate over weaponTypesMissile and pick suitable one based on engagementRange (and dynamic launch zone for missiles) + // Prioritize by: + // 1. Lasers + // 2. Guns + // 3. AA missiles + List.Enumerator item = weaponTypesMissile.GetEnumerator(); + while (item.MoveNext()) + { + if (item.Current == null) continue; + // candidate, check engagement envelope + if (!CheckEngagementEnvelope(item.Current, distance)) continue; + // weapon usable, if missile continue looking for lasers/guns, else take it + WeaponClasses candidateClass = item.Current.GetWeaponClass(); + + if (candidateClass == WeaponClasses.DefenseLaser) + { + float canidateYTraverse = ((ModuleWeapon)item.Current).yawRange; + float canidatePTraverse = ((ModuleWeapon)item.Current).maxPitch; + + if (targetWeapon != null && (canidateYTraverse > 0 || canidatePTraverse > 0)) //prioritize turreted lasers + { + targetWeapon = item.Current; + break; + } + targetWeapon = item.Current; // then any laser + break; + } + + if (candidateClass == WeaponClasses.Gun) + { + // For point defense, favor turrets and RoF + float candidateRPM = ((ModuleWeapon)item.Current).roundsPerMinute; + float canidateYTraverse = ((ModuleWeapon)item.Current).yawRange; + float canidatePTraverse = ((ModuleWeapon)item.Current).maxPitch; + if (targetWeapon != null && (canidateYTraverse > 0 || canidatePTraverse > 0)) + { + candidateRPM *= 2.0f; // weight selection towards turrets + } + if ((targetWeapon != null) && (targetWeaponRPM > candidateRPM)) + continue; //dont replace better guns (but do replace missiles) + + targetWeapon = item.Current; + targetWeaponRPM = candidateRPM; + } + + if (candidateClass != WeaponClasses.Missile) continue; + // TODO: for AA, favour higher thrust+turnDPS + + MissileLauncher mlauncher = item.Current as MissileLauncher; + float candidateTDPS = 0f; + + if (mlauncher != null) + { + candidateTDPS = mlauncher.thrust + mlauncher.maxTurnRateDPS; + } + else + { //is modular missile + BDModularGuidance mm = item.Current as BDModularGuidance; + candidateTDPS = 5000; + } + + if ((targetWeapon != null) && ((targetWeapon.GetWeaponClass() == WeaponClasses.Gun) || (targetWeaponTDPS > candidateTDPS))) + continue; //dont replace guns or better missiles + + targetWeapon = item.Current; + targetWeaponTDPS = candidateTDPS; + } + item.Dispose(); + } + + //else if (!target.isLanded) + else if (target.isFlying) + { + // iterate over weaponTypesAir and pick suitable one based on engagementRange (and dynamic launch zone for missiles) + // Prioritize by: + // 1. AA missiles, if range > gunRange + // 1. Lasers + // 2. Guns + // + List.Enumerator item = weaponTypesAir.GetEnumerator(); + while (item.MoveNext()) + { + if (item.Current == null) continue; + // candidate, check engagement envelope + if (!CheckEngagementEnvelope(item.Current, distance)) continue; + // weapon usable, if missile continue looking for lasers/guns, else take it + WeaponClasses candidateClass = item.Current.GetWeaponClass(); + + if (candidateClass == WeaponClasses.DefenseLaser) + { + // For AA, favour higher power/turreted + float candidatePower = ((ModuleWeapon)item.Current).laserDamage; + bool canidateGimbal = ((ModuleWeapon)item.Current).turret; + float canidateTraverse = ((ModuleWeapon)item.Current).yawRange; + if ((targetWeapon != null) && (canidateGimbal = true && canidateTraverse > 0)) + { + candidatePower *= 1.5f; // weight selection towards turreted lasers + } + if ((targetWeapon != null) && (targetLaserDamage > candidatePower)) + continue; //dont replace better guns (but do replace missiles) + + targetWeapon = item.Current; + targetLaserDamage = candidatePower; + if (distance <= gunRange) + break; + } + + if (candidateClass == WeaponClasses.Gun) + { + // For AAA, favour higher RPM and turrets + float candidateRPM = ((ModuleWeapon)item.Current).roundsPerMinute; + bool canidateGimbal = ((ModuleWeapon)item.Current).turret; + float canidateTraverse = ((ModuleWeapon)item.Current).yawRange; + bool canidatePFuzed = ((ModuleWeapon)item.Current).proximityDetonation; + bool canidateVTFuzed = ((ModuleWeapon)item.Current).airDetonation; + if ((targetWeapon != null) && (canidateGimbal = true && canidateTraverse > 0)) + { + candidateRPM *= 1.5f; // weight selection towards turrets + } + if (targetWeapon != null && (canidatePFuzed || canidateVTFuzed)) + { + candidateRPM *= 1.5f; // weight selection towards flak ammo + } + if ((targetWeapon != null) && (targetWeaponRPM > candidateRPM)) + continue; //dont replace better guns (but do replace missiles) + + targetWeapon = item.Current; + targetWeaponRPM = candidateRPM; + } + + if (candidateClass != WeaponClasses.Missile) continue; + MissileLauncher mlauncher = item.Current as MissileLauncher; + float candidateTDPS = 0f; + + if (mlauncher != null) + { + candidateTDPS = mlauncher.thrust + mlauncher.maxTurnRateDPS; + } + else + { //is modular missile + BDModularGuidance mm = item.Current as BDModularGuidance; + candidateTDPS = 5000; + } + + if (targetWeapon == null) + { + targetWeapon = item.Current; + targetWeaponTDPS = candidateTDPS; + } + else if (distance > gunRange) + { + if (targetWeapon.GetWeaponClass() == WeaponClasses.Gun || targetWeaponTDPS > candidateTDPS) + continue; //dont replace guns or better missiles + + targetWeapon = item.Current; + targetWeaponTDPS = candidateTDPS; + } + } + item.Dispose(); + } + else if (target.isLandedOrSurfaceSplashed) + { + // iterate over weaponTypesGround and pick suitable one based on engagementRange (and dynamic launch zone for missiles) + // Prioritize by: + // 1. ground attack missiles (cruise, gps, unguided) if target not moving + // 2. ground attack missiles (guided) if target is moving + // 3. Bombs / Rockets + // 4. Guns + List.Enumerator item = weaponTypesGround.GetEnumerator(); + while (item.MoveNext()) + { + if (item.Current == null) continue; + // candidate, check engagement envelope + if (!CheckEngagementEnvelope(item.Current, distance)) continue; + // weapon usable, if missile continue looking for lasers/guns, else take it + WeaponClasses candidateClass = item.Current.GetWeaponClass(); + + if (candidateClass == WeaponClasses.Missile) + { + // Priority Sequence: + // - Antiradiation + // - guided missiles + // - by blast strength + float canidateYield = ((MissileBase)item.Current).GetBlastRadius(); + double srfSpeed = currentTarget.Vessel.horizontalSrfSpeed; + bool canidateAGM = false; + bool canidateAntiRad = false; + + if (srfSpeed < 1) // set higher than 0 in case of physics jitteriness + { + if (((MissileBase)item.Current).TargetingMode == MissileBase.TargetingModes.Gps || + (((MissileBase)item.Current).GuidanceMode == MissileBase.GuidanceModes.Cruise || + ((MissileBase)item.Current).GuidanceMode == MissileBase.GuidanceModes.AGMBallistic || + ((MissileBase)item.Current).GuidanceMode == MissileBase.GuidanceModes.None)) + { + if (targetWeapon != null && targetYield > canidateYield) continue; //prioritize biggest Boom + targetYield = canidateYield; + canidateAGM = true; + targetWeapon = item.Current; + if (distance > ((MissileBase)item.Current).engageRangeMin) + break; + } + } + if (((MissileBase)item.Current).TargetingMode == MissileBase.TargetingModes.AntiRad && (rwr && rwr.rwrEnabled)) + {// make it so this only selects antirad when hostile radar + for (int i = 0; i < rwr.pingsData.Length; i++) + { + if (rwr.pingsData[i].signalStrength == 0 || rwr.pingsData[i].signalStrength == 5) + { + if ((rwr.pingWorldPositions[i] - guardTarget.CoM).sqrMagnitude < 20 * 20) //is current target a hostile radar source? + { + canidateAntiRad = true; + } + } + } + if (canidateAntiRad) + { + if (targetWeapon != null && targetYield > canidateYield) continue; //prioritize biggest Boom + targetYield = canidateYield; + targetWeapon = item.Current; + canidateAGM = true; + } + } + else if (((MissileBase)item.Current).TargetingMode == MissileBase.TargetingModes.Laser) + { + if ((targetWeapon != null && targetYield > canidateYield) && !canidateAntiRad) continue; + canidateAGM = true; + targetYield = canidateYield; + targetWeapon = item.Current; + } + else + { + if (!canidateAGM) + { + if (targetWeapon != null && targetYield > canidateYield) continue; + targetYield = canidateYield; + targetWeapon = item.Current; + } + } + } + + // TargetInfo.isLanded includes splashed but not underwater, for whatever reasons. + // If target is splashed, and we have torpedoes, use torpedoes, because, obviously, + // torpedoes are the best kind of sausage for splashed targets, + // almost as good as STS missiles, which we don't have. + if (candidateClass == WeaponClasses.SLW && target.isSplashed) + { + float canidateYield = ((MissileBase)item.Current).GetBlastRadius(); + // not sure on the desired selection priority algorithm, so placeholder By Yield for now + float droptime = ((MissileBase)item.Current).dropTime; + + if (droptime > 0) //make sure it's an airdropped torpedo if flying + { + if (!vessel.LandedOrSplashed) + { + if (targetYield > canidateYield) continue; + targetYield = canidateYield; + targetWeapon = item.Current; + if (distance > gunRange) + break; + } + } + } + + if (candidateClass == WeaponClasses.Bomb) + { + // only useful if we are flying + float canidateYield = ((MissileBase)item.Current).GetBlastRadius(); + if (!vessel.LandedOrSplashed) + { + // Priority Sequence: + // - guided (JDAM) + // - by blast strength + // - find way to implement cluster bomb selection priority? + if (((MissileBase)item.Current).GuidanceMode == MissileBase.GuidanceModes.AGMBallistic) + { + if (targetYield > canidateYield) continue; //prioritize biggest Boom + targetYield = canidateYield; + targetWeapon = item.Current; + if (targetWeapon != null && distance > canidateYield) // don't drop bombs when within blast radius + break; //Prioritize guided bombs + } + if (((MissileBase)item.Current).GuidanceMode == MissileBase.GuidanceModes.None) + { + if (targetYield > canidateYield) continue; + targetYield = canidateYield; + targetWeapon = item.Current; + if (targetWeapon != null && distance > canidateYield) + break; //then standard + } + } + } + + if (candidateClass == WeaponClasses.Rocket) + { + float canidateRocketPower = ((RocketLauncher)item.Current).blastForce; + + if ((targetWeapon != null) && (targetWeapon.GetWeaponClass() == WeaponClasses.Bomb)) continue; + // dont replace bombs + + if ((targetWeapon != null) && (targetRocketPower > canidateRocketPower)) + continue; //don't replace higher yield rockets + targetWeapon = item.Current; + targetRocketPower = canidateRocketPower; + } + + if ((candidateClass != WeaponClasses.Gun)) continue; + // Flying: prefer bombs/rockets/missiles + if (!vessel.LandedOrSplashed) + if (targetWeapon != null) + // dont replace bombs/rockets + continue; + // else: + if ((distance > gunRange) && (targetWeapon != null)) + continue; + // For Ground Attack, favour higher blast strength + float candidateImpact = ((ModuleWeapon)item.Current).cannonShellPower * ((ModuleWeapon)item.Current).cannonShellRadius + ((ModuleWeapon)item.Current).cannonShellHeat; + + if ((targetWeapon != null) && (targetWeaponImpact > candidateImpact)) + continue; //dont replace better guns + + targetWeapon = item.Current; + targetWeaponImpact = candidateImpact; + } + } + else if (target.isUnderwater) + { + // iterate over weaponTypesSLW (Ship Launched Weapons) and pick suitable one based on engagementRange + // Prioritize by: + // 1. Depth Charges + // 2. Torpedos + List.Enumerator item = weaponTypesSLW.GetEnumerator(); + while (item.MoveNext()) + { + if (item.Current == null) continue; + if (CheckEngagementEnvelope(item.Current, distance)) + { + if (item.Current.GetMissileType().ToLower() == "depthcharge") + { + targetWeapon = item.Current; + break; + } + if (item.Current.GetMissileType().ToLower() != "torpedo") continue; + targetWeapon = item.Current; + break; + } + } + item.Dispose(); + } + + // return result of weapon selection + if (targetWeapon != null) + { + //update the legacy lists & arrays, especially selectedWeapon and weaponIndex + selectedWeapon = targetWeapon; + // find it in weaponArray + for (int i = 1; i < weaponArray.Length; i++) + { + weaponIndex = i; + if (selectedWeapon.GetShortName() == weaponArray[weaponIndex].GetShortName()) + { + break; + } + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory] : " + vessel.vesselName + " - Selected weapon " + selectedWeapon.GetShortName()); + } + + PrepareWeapons(); + DisplaySelectedWeaponMessage(); + return true; + } + else + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory] : " + vessel.vesselName + " - No weapon selected."); + } + + selectedWeapon = null; + weaponIndex = 0; + return false; + } + } + + // extension for feature_engagementenvelope: check engagement parameters of the weapon if it can be used against the current target + bool CheckEngagementEnvelope(IBDWeapon weaponCandidate, float distanceToTarget) + { + EngageableWeapon engageableWeapon = weaponCandidate as EngageableWeapon; + + if (engageableWeapon == null) return true; + if (!engageableWeapon.engageEnabled) return true; + if (distanceToTarget < engageableWeapon.GetEngagementRangeMin()) return false; + if (distanceToTarget > engageableWeapon.GetEngagementRangeMax()) return false; + + switch (weaponCandidate.GetWeaponClass()) + { + case WeaponClasses.DefenseLaser: + // TODO: is laser treated like a gun? + + case WeaponClasses.Gun: + { + ModuleWeapon gun = (ModuleWeapon)weaponCandidate; + + // check yaw range of turret + ModuleTurret turret = gun.turret; + float gimbalTolerance = vessel.LandedOrSplashed ? 0 : 15; + if (turret != null) + if (!TargetInTurretRange(turret, gimbalTolerance)) + return false; + + // check overheat + if (gun.isOverheated) + return false; + + // check ammo + if (CheckAmmo(gun)) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory] : " + vessel.vesselName + " - Firing possible with " + weaponCandidate.GetShortName()); + } + return true; + } + break; + } + + case WeaponClasses.Missile: + { + MissileBase ml = (MissileBase)weaponCandidate; + + // lock radar if needed + if (ml.TargetingMode == MissileBase.TargetingModes.Radar) + using (List.Enumerator rd = radars.GetEnumerator()) + while (rd.MoveNext()) + { + if (rd.Current != null || rd.Current.canLock) + rd.Current.EnableRadar(); + } + + // check DLZ + MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(ml, guardTarget.Velocity(), guardTarget.transform.position); + if (vessel.srfSpeed > ml.minLaunchSpeed && distanceToTarget < dlz.maxLaunchRange && distanceToTarget > dlz.minLaunchRange) + { + return true; + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory] : " + vessel.vesselName + " - Failed DLZ test: " + weaponCandidate.GetShortName()); + } + break; + } + + case WeaponClasses.Bomb: + if (!vessel.LandedOrSplashed) + return true; // TODO: bomb always allowed? + break; + + case WeaponClasses.Rocket: + { + RocketLauncher rocketlauncher = (RocketLauncher)weaponCandidate; + // check yaw range of turret + var turret = rocketlauncher.turret; + float gimbalTolerance = vessel.LandedOrSplashed ? 0 : 15; + if (turret != null) + if (TargetInTurretRange(turret, gimbalTolerance)) + return true; + break; + } + + case WeaponClasses.SLW: + { + // Enable sonar, or radar, if no sonar is found. + if (((MissileBase)weaponCandidate).TargetingMode == MissileBase.TargetingModes.Radar) + using (List.Enumerator rd = radars.GetEnumerator()) + while (rd.MoveNext()) + { + if (rd.Current != null || rd.Current.canLock) + rd.Current.EnableRadar(); + } + return true; + } + + default: + throw new ArgumentOutOfRangeException(); + } + + return false; + } + + void SetTarget(TargetInfo target) + { + if (target) + { + if (currentTarget) + { + currentTarget.Disengage(this); + } + target.Engage(this); + currentTarget = target; + guardTarget = target.Vessel; + } + else + { + if (currentTarget) + { + currentTarget.Disengage(this); + } + guardTarget = null; + currentTarget = null; + } + } + + #endregion Smart Targeting + + public bool CanSeeTarget(TargetInfo target) + { + // fix cheating: we can see a target IF we either have a visual on it, OR it has been detected on radar/sonar + // but to prevent AI from stopping an engagement just because a target dropped behind a small hill 5 seconds ago, clamp the timeout to 30 seconds + // i.e. let's have at least some object permanence :) + // (Ideally, I'd love to have "stale targets", where AI would attack the last known position, but that's a feature for the future) + if (target.detectedTime.TryGetValue(Team, out float detectedTime) && Time.time - detectedTime < Mathf.Max(targetScanInterval, 30)) + return true; + + // can we get a visual sight of the target? + if ((target.Vessel.transform.position - transform.position).sqrMagnitude < guardRange * guardRange) + { + if (RadarUtils.TerrainCheck(target.Vessel.transform.position, transform.position)) + { + return false; + } + + return true; + } + + return false; + } + + /// + /// Override for legacy targeting only! Remove when removing legcy mode! + /// + /// + /// + public bool CanSeeTarget(Vessel target) + { + // can we get a visual sight of the target? + if ((target.transform.position - transform.position).sqrMagnitude < guardRange * guardRange) + { + if (RadarUtils.TerrainCheck(target.transform.position, transform.position)) + { + return false; + } + + return true; + } + + return false; + } + + void SearchForRadarSource() + { + antiRadTargetAcquired = false; + + if (rwr && rwr.rwrEnabled) + { + float closestAngle = 360; + MissileBase missile = CurrentMissile; + + if (!missile) return; + + float maxOffBoresight = missile.maxOffBoresight; + + if (missile.TargetingMode != MissileBase.TargetingModes.AntiRad) return; + + for (int i = 0; i < rwr.pingsData.Length; i++) + { + if (rwr.pingsData[i].exists && (rwr.pingsData[i].signalStrength == 0 || rwr.pingsData[i].signalStrength == 5)) + { + float angle = Vector3.Angle(rwr.pingWorldPositions[i] - missile.transform.position, missile.GetForwardTransform()); + + if (angle < closestAngle && angle < maxOffBoresight) + { + closestAngle = angle; + antiRadiationTarget = rwr.pingWorldPositions[i]; + antiRadTargetAcquired = true; + } + } + } + } + } + + void SearchForLaserPoint() + { + MissileBase ml = CurrentMissile; + if (!ml || ml.TargetingMode != MissileBase.TargetingModes.Laser) + { + return; + } + + MissileLauncher launcher = ml as MissileLauncher; + if (launcher != null) + { + foundCam = BDATargetManager.GetLaserTarget(launcher, + launcher.GuidanceMode == MissileBase.GuidanceModes.BeamRiding); + } + else + { + foundCam = BDATargetManager.GetLaserTarget((BDModularGuidance)ml, false); + } + + if (foundCam) + { + laserPointDetected = true; + } + else + { + laserPointDetected = false; + } + } + + void SearchForHeatTarget() + { + if (CurrentMissile != null) + { + if (!CurrentMissile || CurrentMissile.TargetingMode != MissileBase.TargetingModes.Heat) + { + return; + } + + float scanRadius = CurrentMissile.lockedSensorFOV * 0.5f; + float maxOffBoresight = CurrentMissile.maxOffBoresight * 0.85f; + + if (vesselRadarData && vesselRadarData.locked) + { + heatTarget = vesselRadarData.lockedTargetData.targetData; + } + + Vector3 direction = + heatTarget.exists && Vector3.Angle(heatTarget.position - CurrentMissile.MissileReferenceTransform.position, CurrentMissile.GetForwardTransform()) < maxOffBoresight ? + heatTarget.predictedPosition - CurrentMissile.MissileReferenceTransform.position + : CurrentMissile.GetForwardTransform(); + + heatTarget = BDATargetManager.GetHeatTarget(vessel,vessel, new Ray(CurrentMissile.MissileReferenceTransform.position + (50 * CurrentMissile.GetForwardTransform()), direction), scanRadius, CurrentMissile.heatThreshold, CurrentMissile.allAspect, this); + } + } + + bool CrossCheckWithRWR(TargetInfo v) + { + bool matchFound = false; + if (rwr && rwr.rwrEnabled) + { + for (int i = 0; i < rwr.pingsData.Length; i++) + { + if (rwr.pingsData[i].exists && (rwr.pingWorldPositions[i] - v.position).sqrMagnitude < 20 * 20) + { + matchFound = true; + break; + } + } + } + + return matchFound; + } + + public void SendTargetDataToMissile(MissileBase ml) + { //TODO BDModularGuidance: implement all targetings on base + if (ml.TargetingMode == MissileBase.TargetingModes.Laser && laserPointDetected) + { + ml.lockedCamera = foundCam; + } + else if (ml.TargetingMode == MissileBase.TargetingModes.Gps) + { + if (designatedGPSCoords != Vector3d.zero) + { + ml.targetGPSCoords = designatedGPSCoords; + ml.TargetAcquired = true; + } + } + else if (ml.TargetingMode == MissileBase.TargetingModes.Heat && heatTarget.exists) + { + ml.heatTarget = heatTarget; + heatTarget = TargetSignatureData.noTarget; + } + else if (ml.TargetingMode == MissileBase.TargetingModes.Radar && vesselRadarData && vesselRadarData.locked)//&& radar && radar.lockedTarget.exists) + { + ml.radarTarget = vesselRadarData.lockedTargetData.targetData; + ml.vrd = vesselRadarData; + vesselRadarData.LastMissile = ml; + } + else if (ml.TargetingMode == MissileBase.TargetingModes.AntiRad && antiRadTargetAcquired) + { + ml.TargetAcquired = true; + ml.targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(antiRadiationTarget, + vessel.mainBody); + } + } + + #endregion Targeting + + #region Guard + + public void ResetGuardInterval() + { + targetScanTimer = 0; + } + + void GuardMode() + { + if (!gameObject.activeInHierarchy) return; + if (BDArmorySettings.PEACE_MODE) return; + + UpdateGuardViewScan(); + + //setting turrets to guard mode + if (selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) + { + //make this not have to go every frame + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (weapon.Current.GetShortName() != selectedWeapon.GetShortName()) continue; //want to find all weapons in WeaponGroup, rather than all weapons of parttype + weapon.Current.EnableWeapon(); + weapon.Current.aiControlled = true; + if (weapon.Current.yawRange >= 5 && (weapon.Current.maxPitch - weapon.Current.minPitch) >= 5) + weapon.Current.maxAutoFireCosAngle = 1; + else + weapon.Current.maxAutoFireCosAngle = vessel.LandedOrSplashed ? 0.9993908f : 0.9975641f; //2 : 4 degrees + } + weapon.Dispose(); + } + + if (!guardTarget && selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) + { + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (weapon.Current.GetShortName() != selectedWeapon.GetShortName()) continue; + weapon.Current.autoFire = false; + weapon.Current.visualTargetVessel = null; + } + weapon.Dispose(); + } + + if (missilesAway < 0) + missilesAway = 0; + + if (missileIsIncoming) + { + if (!isLegacyCMing) + { + StartCoroutine(LegacyCMRoutine()); + } + + targetScanTimer -= Time.fixedDeltaTime; //advance scan timing (increased urgency) + } + + //scan and acquire new target + if (Time.time - targetScanTimer > targetScanInterval) + { + targetScanTimer = Time.time; + + if (!guardFiringMissile) + { + SetTarget(null); + + SmartFindTarget(); + + if (guardTarget == null || selectedWeapon == null) + { + SetCargoBays(); + return; + } + + //firing + if (weaponIndex > 0) + { + if (selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || selectedWeapon.GetWeaponClass() == WeaponClasses.SLW) + { + bool launchAuthorized = true; + bool pilotAuthorized = true; + //(!pilotAI || pilotAI.GetLaunchAuthorization(guardTarget, this)); + + float targetAngle = Vector3.Angle(-transform.forward, guardTarget.transform.position - transform.position); + float targetDistance = Vector3.Distance(currentTarget.position, transform.position); + MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(CurrentMissile, guardTarget.Velocity(), guardTarget.CoM); + + if (targetAngle > guardAngle / 2) //dont fire yet if target out of guard angle + { + launchAuthorized = false; + } + else if (targetDistance >= dlz.maxLaunchRange || targetDistance <= dlz.minLaunchRange) //fire the missile only if target is further than missiles min launch range + { + launchAuthorized = false; + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]:" + vessel.vesselName + " launchAuth=" + launchAuthorized + ", pilotAut=" + pilotAuthorized + ", missilesAway/Max=" + missilesAway + "/" + maxMissilesOnTarget); + + if (missilesAway < maxMissilesOnTarget) + { + if (!guardFiringMissile && launchAuthorized) + { + StartCoroutine(GuardMissileRoutine()); + } + } + else if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]:" + vessel.vesselName + " waiting for missile to be ready..."); + } + + if (!launchAuthorized || !pilotAuthorized || missilesAway >= maxMissilesOnTarget) + { + targetScanTimer -= 0.5f * targetScanInterval; + } + } + else if (selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) + { + if (!guardFiringMissile) + { + StartCoroutine(GuardBombRoutine()); + } + } + else if (selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || + selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket || + selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser) + { + StartCoroutine(GuardTurretRoutine()); + } + } + } + SetCargoBays(); + } + + if (overrideTimer > 0) + { + overrideTimer -= TimeWarp.fixedDeltaTime; + } + else + { + overrideTimer = 0; + overrideTarget = null; + } + } + + void UpdateGuardViewScan() + { + ViewScanResults results = RadarUtils.GuardScanInDirection(this, transform, guardAngle, guardRange); + + if (results.foundMissile) + { + if (rwr && !rwr.rwrEnabled) rwr.EnableRWR(); + if (rwr && rwr.rwrEnabled && !rwr.displayRWR) rwr.displayRWR = true; + } + + if (results.foundHeatMissile) + { + StartCoroutine(UnderAttackRoutine()); + + if (!isFlaring) + { + StartCoroutine(FlareRoutine(2.5f)); + StartCoroutine(ResetMissileThreatDistanceRoutine()); + } + incomingThreatPosition = results.threatPosition; + + if (results.threatVessel) + { + if (!incomingMissileVessel || + (incomingMissileVessel.transform.position - vessel.transform.position).sqrMagnitude > + (results.threatVessel.transform.position - vessel.transform.position).sqrMagnitude) + { + incomingMissileVessel = results.threatVessel; + } + } + } + + if (results.foundRadarMissile) + { + StartCoroutine(UnderAttackRoutine()); + + FireChaff(); + FireECM(); + + incomingThreatPosition = results.threatPosition; + + if (results.threatVessel) + { + if (!incomingMissileVessel || + (incomingMissileVessel.transform.position - vessel.transform.position).sqrMagnitude > + (results.threatVessel.transform.position - vessel.transform.position).sqrMagnitude) + { + incomingMissileVessel = results.threatVessel; + } + } + } + + if (results.foundAGM) + { + StartCoroutine(UnderAttackRoutine()); + + //do smoke CM here. + if (targetMissiles && guardTarget == null) + { + //targetScanTimer = Mathf.Min(targetScanInterval, Time.time - targetScanInterval + 0.5f); + targetScanTimer -= targetScanInterval / 2; + } + } + + incomingMissileDistance = Mathf.Min(results.missileThreatDistance, incomingMissileDistance); + + if (results.firingAtMe) + { + StartCoroutine(UnderAttackRoutine()); + + incomingThreatPosition = results.threatPosition; + if (ufRoutine != null) + { + StopCoroutine(ufRoutine); + underFire = false; + } + if (results.threatWeaponManager != null) + { + TargetInfo nearbyFriendly = BDATargetManager.GetClosestFriendly(this); + TargetInfo nearbyThreat = BDATargetManager.GetTargetFromWeaponManager(results.threatWeaponManager); + + if (nearbyThreat?.weaponManager != null && nearbyFriendly?.weaponManager != null) + if (Team.IsEnemy(nearbyThreat.weaponManager.Team) && + nearbyFriendly.weaponManager.Team == Team) + //turns out that there's no check for AI on the same team going after each other due to this. Who knew? + { + if (nearbyThreat == currentTarget && nearbyFriendly.weaponManager.currentTarget != null) + //if being attacked by the current target, switch to the target that the nearby friendly was engaging instead + { + SetOverrideTarget(nearbyFriendly.weaponManager.currentTarget); + nearbyFriendly.weaponManager.SetOverrideTarget(nearbyThreat); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: " + vessel.vesselName + " called for help from " + + nearbyFriendly.Vessel.vesselName + " and took its target in return"); + //basically, swap targets to cover each other + } + else + { + //otherwise, continue engaging the current target for now + nearbyFriendly.weaponManager.SetOverrideTarget(nearbyThreat); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: " + vessel.vesselName + " called for help from " + + nearbyFriendly.Vessel.vesselName); + } + } + } + ufRoutine = StartCoroutine(UnderFireRoutine()); + } + } + + public void ForceScan() + { + targetScanTimer = -100; + } + + void StartGuardTurretFiring() + { + if (!guardTarget) return; + if (selectedWeapon == null) return; + + if (selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) + { + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (weapon.Current.GetShortName() != selectedWeaponString) continue; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Setting rocket to auto fire"); + } + weapon.Current.legacyGuardTarget = guardTarget; + weapon.Current.autoFireStartTime = Time.time; + //weapon.Current.autoFireDuration = targetScanInterval / 2; + weapon.Current.autoFireDuration = (fireBurstLength < 0.5) ? targetScanInterval / 2 : fireBurstLength; + weapon.Current.autoRippleRate = rippleFire ? rippleRPM : 0; + } + weapon.Dispose(); + } + else + { + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (weapon.Current.GetShortName() != selectedWeapon.GetShortName()) continue; + weapon.Current.visualTargetVessel = guardTarget; + weapon.Current.autoFireTimer = Time.time; + //weapon.Current.autoFireLength = 3 * targetScanInterval / 4; + weapon.Current.autoFireLength = (fireBurstLength < 0.5) ? targetScanInterval / 2 : fireBurstLength; + } + weapon.Dispose(); + } + } + + public void SetOverrideTarget(TargetInfo target) + { + overrideTarget = target; + targetScanTimer = -100; + } + + public void UpdateMaxGuardRange() + { + UI_FloatRange rangeEditor = (UI_FloatRange)Fields["guardRange"].uiControlEditor; + rangeEditor.maxValue = BDArmorySettings.MAX_GUARD_VISUAL_RANGE; + } + + // moved from pilot AI, as it does not really do anything AI related? + bool GetLaunchAuthorization(Vessel targetV, MissileFire mf) + { + bool launchAuthorized = false; + Vector3 target = targetV.transform.position; + MissileBase missile = mf.CurrentMissile; + if (missile != null) + { + if (!targetV.LandedOrSplashed) + { + target = MissileGuidance.GetAirToAirFireSolution(missile, targetV); + } + + float boresightFactor = targetV.LandedOrSplashed ? 0.75f : 0.35f; + + //if(missile.TargetingMode == MissileBase.TargetingModes.Gps) maxOffBoresight = 45; + + float fTime = 2f; + Vector3 futurePos = target + (targetV.Velocity() * fTime); + Vector3 myFuturePos = vessel.ReferenceTransform.position + (vessel.Velocity() * fTime); + bool fDot = Vector3.Dot(vessel.ReferenceTransform.up, futurePos - myFuturePos) > 0; //check target won't likely be behind me soon + + if (fDot && Vector3.Angle(missile.GetForwardTransform(), target - missile.transform.position) < missile.maxOffBoresight * boresightFactor) + { + launchAuthorized = true; + } + } + + return launchAuthorized; + } + + /// + /// Check if AI is online and can target the current guardTarget with direct fire weapons + /// + /// true if AI might fire + bool AIMightDirectFire() + { + return (AI == null || !AI.pilotEnabled || !AI.CanEngage() || !guardTarget || !AI.IsValidFixedWeaponTarget(guardTarget)); + } + + #endregion Guard + + #region Turret + + int CheckTurret(float distance) + { + if (weaponIndex == 0 || selectedWeapon == null || + !(selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || + selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser || + selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket)) + { + return 2; + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Checking turrets"); + } + float finalDistance = distance; + //vessel.LandedOrSplashed ? distance : distance/2; //decrease distance requirement if airborne + + if (selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) + { + List.Enumerator rl = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rl.MoveNext()) + { + if (rl.Current == null) continue; + if (rl.Current.part.partInfo.title != selectedWeapon.GetPart().partInfo.title) continue; + float gimbalTolerance = vessel.LandedOrSplashed ? 0 : 15; + if (!(rl.Current.maxTargetingRange >= finalDistance) || + !TargetInTurretRange(rl.Current.turret, gimbalTolerance)) continue; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + selectedWeapon + " is valid!"); + } + return 1; + } + rl.Dispose(); + } + else + { + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (weapon.Current.GetShortName() != selectedWeapon.GetShortName()) continue; + float gimbalTolerance = vessel.LandedOrSplashed ? 0 : 15; + if (((AI != null && AI.pilotEnabled && AI.CanEngage()) || (TargetInTurretRange(weapon.Current.turret, gimbalTolerance))) && weapon.Current.maxEffectiveDistance >= finalDistance) + { + if (weapon.Current.isOverheated) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + selectedWeapon + " is overheated!"); + } + return -1; + } + if (CheckAmmo(weapon.Current) || BDArmorySettings.INFINITE_AMMO) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + selectedWeapon + " is valid!"); + } + return 1; + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + selectedWeapon + " has no ammo."); + } + return -1; + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: " + selectedWeapon + " cannot reach target (" + distance + " vs " + weapon.Current.maxEffectiveDistance + ", yawRange: " + weapon.Current.yawRange + "). Continuing."); + } + //else return 0; + } + weapon.Dispose(); + } + return 2; + } + + bool TargetInTurretRange(ModuleTurret turret, float tolerance) + { + if (!turret) + { + return false; + } + + if (!guardTarget) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Checking turret range but no guard target"); + } + return false; + } + + Transform turretTransform = turret.yawTransform.parent; + Vector3 direction = guardTarget.transform.position - turretTransform.position; + Vector3 directionYaw = Vector3.ProjectOnPlane(direction, turretTransform.up); + Vector3 directionPitch = Vector3.ProjectOnPlane(direction, turretTransform.right); + + float angleYaw = Vector3.Angle(turretTransform.forward, directionYaw); + float signedAnglePitch = 90 - Vector3.Angle(turretTransform.up, directionPitch); + bool withinPitchRange = (signedAnglePitch >= turret.minPitch - tolerance && signedAnglePitch <= turret.maxPitch + tolerance); + + if (angleYaw < (turret.yawRange / 2) + tolerance && withinPitchRange) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Checking turret range - target is INSIDE gimbal limits! signedAnglePitch: " + signedAnglePitch + ", minPitch: " + turret.minPitch + ", maxPitch: " + turret.maxPitch); + } + return true; + } + else + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Checking turret range - target is OUTSIDE gimbal limits! signedAnglePitch: " + signedAnglePitch + ", minPitch: " + turret.minPitch + ", maxPitch: " + turret.maxPitch + ", angleYaw: " + angleYaw); + } + return false; + } + } + + bool CheckAmmo(ModuleWeapon weapon) + { + string ammoName = weapon.ammoName; + List.Enumerator p = vessel.parts.GetEnumerator(); + while (p.MoveNext()) + { + if (p.Current == null) continue; + IEnumerator resource = p.Current.Resources.GetEnumerator(); + while (resource.MoveNext()) + { + if (resource.Current == null) continue; + if (resource.Current.resourceName != ammoName) continue; + if (resource.Current.amount > 0) + { + return true; + } + } + resource.Dispose(); + } + p.Dispose(); + + return false; + } + + void ToggleTurret() + { + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (selectedWeapon == null || weapon.Current.GetShortName() != selectedWeapon.GetShortName()) + { + weapon.Current.DisableWeapon(); + } + else + { + weapon.Current.EnableWeapon(); + } + } + weapon.Dispose(); + } + + #endregion Turret + + #region Aimer + + void BombAimer() + { + if (selectedWeapon == null) + { + showBombAimer = false; + return; + } + if (!bombPart || selectedWeapon.GetPart() != bombPart) + { + if (selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) + { + bombPart = selectedWeapon.GetPart(); + } + else + { + showBombAimer = false; + return; + } + } + + showBombAimer = + ( + !MapView.MapIsEnabled && + vessel.isActiveVessel && + selectedWeapon != null && + selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb && + bombPart != null && + BDArmorySettings.DRAW_AIMERS && + vessel.verticalSpeed < 50 && + AltitudeTrigger() + ); + + if (!showBombAimer && (!guardMode || weaponIndex <= 0 || + selectedWeapon.GetWeaponClass() != WeaponClasses.Bomb)) return; + MissileBase ml = bombPart.GetComponent(); + + float simDeltaTime = 0.1f; + float simTime = 0; + Vector3 dragForce = Vector3.zero; + Vector3 prevPos = ml.MissileReferenceTransform.position; + Vector3 currPos = ml.MissileReferenceTransform.position; + //Vector3 simVelocity = vessel.rb_velocity; + Vector3 simVelocity = vessel.Velocity(); //Issue #92 + + MissileLauncher launcher = ml as MissileLauncher; + if (launcher != null) + { + simVelocity += launcher.decoupleSpeed * + (launcher.decoupleForward + ? launcher.MissileReferenceTransform.forward + : -launcher.MissileReferenceTransform.up); + } + else + { //TODO: BDModularGuidance review this value + simVelocity += 5 * -launcher.MissileReferenceTransform.up; + } + + List pointPositions = new List(); + pointPositions.Add(currPos); + + prevPos = ml.MissileReferenceTransform.position; + currPos = ml.MissileReferenceTransform.position; + + bombAimerPosition = Vector3.zero; + + bool simulating = true; + while (simulating) + { + prevPos = currPos; + currPos += simVelocity * simDeltaTime; + float atmDensity = + (float) + FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), + FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody); + + simVelocity += FlightGlobals.getGeeForceAtPosition(currPos) * simDeltaTime; + float simSpeedSquared = simVelocity.sqrMagnitude; + + launcher = ml as MissileLauncher; + float drag = 0; + if (launcher != null) + { + drag = launcher.simpleDrag; + if (simTime > launcher.deployTime) + { + drag = launcher.deployedDrag; + } + } + else + { + //TODO:BDModularGuidance drag calculation + drag = ml.vessel.parts.Sum(x => x.dragScalar); + } + + dragForce = (0.008f * bombPart.mass) * drag * 0.5f * simSpeedSquared * atmDensity * simVelocity.normalized; + simVelocity -= (dragForce / bombPart.mass) * simDeltaTime; + + Ray ray = new Ray(prevPos, currPos - prevPos); + RaycastHit hitInfo; + if (Physics.Raycast(ray, out hitInfo, Vector3.Distance(prevPos, currPos), (1 << 15) | (1 << 17))) + { + bombAimerPosition = hitInfo.point; + simulating = false; + } + else if (FlightGlobals.getAltitudeAtPos(currPos) < 0) + { + bombAimerPosition = currPos - + (FlightGlobals.getAltitudeAtPos(currPos) * FlightGlobals.getUpAxis()); + simulating = false; + } + + simTime += simDeltaTime; + pointPositions.Add(currPos); + } + + //debug lines + if (BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) + { + Vector3[] pointsArray = pointPositions.ToArray(); + LineRenderer lr = GetComponent(); + if (!lr) + { + lr = gameObject.AddComponent(); + } + lr.enabled = true; + lr.startWidth = .1f; + lr.endWidth = .1f; + lr.positionCount = pointsArray.Length; + for (int i = 0; i < pointsArray.Length; i++) + { + lr.SetPosition(i, pointsArray[i]); + } + } + else + { + if (gameObject.GetComponent()) + { + gameObject.GetComponent().enabled = false; + } + } + } + + bool AltitudeTrigger() + { + const float maxAlt = 10000; + double asl = vessel.mainBody.GetAltitude(vessel.CoM); + double radarAlt = asl - vessel.terrainAltitude; + + return radarAlt < maxAlt || asl < maxAlt; + } + + #endregion Aimer + } +} diff --git a/BDArmory/Modules/MissileLauncher.cs b/BDArmory/Modules/MissileLauncher.cs new file mode 100644 index 000000000..33bd86a55 --- /dev/null +++ b/BDArmory/Modules/MissileLauncher.cs @@ -0,0 +1,2156 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Core.Utils; +using BDArmory.FX; +using BDArmory.Guidances; +using BDArmory.Misc; +using BDArmory.Parts; +using BDArmory.Radar; +using BDArmory.Targeting; +using BDArmory.UI; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class MissileLauncher : MissileBase + { + #region Variable Declarations + + [KSPField] + public string homingType = "AAM"; + + [KSPField] + public string targetingType = "none"; + + public MissileTurret missileTurret = null; + public BDRotaryRail rotaryRail = null; + + [KSPField] + public string exhaustPrefabPath; + + [KSPField] + public string boostExhaustPrefabPath; + + [KSPField] + public string boostExhaustTransformName; + + #region Aero + + [KSPField] + public bool aero = false; + + [KSPField] + public float liftArea = 0.015f; + + [KSPField] + public float steerMult = 0.5f; + + [KSPField] + public float torqueRampUp = 30f; + Vector3 aeroTorque = Vector3.zero; + float controlAuthority; + float finalMaxTorque; + + [KSPField] + public float aeroSteerDamping = 0; + + #endregion Aero + + [KSPField] + public float maxTorque = 90; + + [KSPField] + public float thrust = 30; + + [KSPField] + public float cruiseThrust = 3; + + [KSPField] + public float boostTime = 2.2f; + + [KSPField] + public float cruiseTime = 45; + + [KSPField] + public float cruiseDelay = 0; + + [KSPField] + public float maxAoA = 35; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_Direction"),//Direction: + UI_Toggle(disabledText = "#LOC_BDArmory_Direction_disabledText", enabledText = "#LOC_BDArmory_Direction_enabledText")]//Lateral--Forward + public bool decoupleForward = false; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DecoupleSpeed"),//Decouple Speed + UI_FloatRange(minValue = 0f, maxValue = 10f, stepIncrement = 0.1f, scene = UI_Scene.Editor)] + public float decoupleSpeed = 0; + + [KSPField] + public float clearanceRadius = 0.14f; + + public override float ClearanceRadius => clearanceRadius; + + [KSPField] + public float clearanceLength = 0.14f; + + public override float ClearanceLength => clearanceLength; + + [KSPField] + public float optimumAirspeed = 220; + + [KSPField] + public float blastRadius = 150; + + [KSPField] + public float blastPower = 25; + + [KSPField] + public float blastHeat = -1; + + [KSPField] + public float maxTurnRateDPS = 20; + + [KSPField] + public bool proxyDetonate = true; + + [KSPField] + public string audioClipPath = string.Empty; + + AudioClip thrustAudio; + + [KSPField] + public string boostClipPath = string.Empty; + + AudioClip boostAudio; + + [KSPField] + public bool isSeismicCharge = false; + + [KSPField] + public float rndAngVel = 0; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxAltitude"),//Max Altitude + UI_FloatRange(minValue = 0f, maxValue = 5000f, stepIncrement = 10f, scene = UI_Scene.All)] + public float maxAltitude = 0f; + + [KSPField] + public string rotationTransformName = string.Empty; + Transform rotationTransform; + + [KSPField] + public bool terminalManeuvering = false; + + [KSPField] + public string terminalGuidanceType = ""; + + [KSPField] + public float terminalGuidanceDistance = 0.0f; + + private bool terminalGuidanceActive; + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_TerminalGuidance"), UI_Toggle(disabledText = "#LOC_BDArmory_false", enabledText = "#LOC_BDArmory_true")]//Terminal Guidance: false true + public bool terminalGuidanceShouldActivate = true; + + [KSPField] + public string explModelPath = "BDArmory/Models/explosion/explosion"; + + public string explSoundPath = "BDArmory/Sounds/explode1"; + + [KSPField] + public bool spoolEngine = false; + + [KSPField] + public bool hasRCS = false; + + [KSPField] + public float rcsThrust = 1; + float rcsRVelThreshold = 0.13f; + KSPParticleEmitter upRCS; + KSPParticleEmitter downRCS; + KSPParticleEmitter leftRCS; + KSPParticleEmitter rightRCS; + KSPParticleEmitter forwardRCS; + float rcsAudioMinInterval = 0.2f; + + private AudioSource audioSource; + public AudioSource sfAudioSource; + List pEmitters; + List gaplessEmitters; + + float cmTimer; + + //deploy animation + [KSPField] + public string deployAnimationName = ""; + + [KSPField] + public float deployedDrag = 0.02f; + + [KSPField] + public float deployTime = 0.2f; + + [KSPField] + public bool useSimpleDrag = false; + + [KSPField] + public float simpleDrag = 0.02f; + + [KSPField] + public float simpleStableTorque = 5; + + [KSPField] + public Vector3 simpleCoD = new Vector3(0, 0, -1); + + [KSPField] + public float agmDescentRatio = 1.45f; + + float currentThrust; + + public bool deployed; + //public float deployedTime; + + AnimationState[] deployStates; + + bool hasPlayedFlyby; + + float debugTurnRate; + + List boosters; + + [KSPField] + public bool decoupleBoosters = false; + + [KSPField] + public float boosterDecoupleSpeed = 5; + + [KSPField] + public float boosterMass = 0; + + Transform vesselReferenceTransform; + + [KSPField] + public string boostTransformName = string.Empty; + List boostEmitters; + List boostGaplessEmitters; + + [KSPField] + public bool torpedo = false; + + [KSPField] + public float waterImpactTolerance = 25; + + //ballistic options + [KSPField] + public bool indirect = false; + + [KSPField] + public bool vacuumSteerable = true; + + public GPSTargetInfo designatedGPSInfo; + + float[] rcsFiredTimes; + KSPParticleEmitter[] rcsTransforms; + + #endregion Variable Declarations + + [KSPAction("Fire Missile")] + public void AGFire(KSPActionParam param) + { + if (BDArmorySetup.Instance.ActiveWeaponManager != null && BDArmorySetup.Instance.ActiveWeaponManager.vessel == vessel) BDArmorySetup.Instance.ActiveWeaponManager.SendTargetDataToMissile(this); + if (missileTurret) + { + missileTurret.FireMissile(this); + } + else if (rotaryRail) + { + rotaryRail.FireMissile(this); + } + else + { + FireMissile(); + } + if (BDArmorySetup.Instance.ActiveWeaponManager != null) BDArmorySetup.Instance.ActiveWeaponManager.UpdateList(); + } + + [KSPEvent(guiActive = true, guiName = "#LOC_BDArmory_FireMissile", active = true)]//Fire Missile + public void GuiFire() + { + if (BDArmorySetup.Instance.ActiveWeaponManager != null && BDArmorySetup.Instance.ActiveWeaponManager.vessel == vessel) BDArmorySetup.Instance.ActiveWeaponManager.SendTargetDataToMissile(this); + if (missileTurret) + { + missileTurret.FireMissile(this); + } + else if (rotaryRail) + { + rotaryRail.FireMissile(this); + } + else + { + FireMissile(); + } + if (BDArmorySetup.Instance.ActiveWeaponManager != null) BDArmorySetup.Instance.ActiveWeaponManager.UpdateList(); + } + + [KSPEvent(guiActive = true, guiActiveEditor = false, active = true, guiName = "#LOC_BDArmory_Jettison")]//Jettison + public override void Jettison() + { + if (missileTurret) return; + + part.decouple(0); + if (BDArmorySetup.Instance.ActiveWeaponManager != null) BDArmorySetup.Instance.ActiveWeaponManager.UpdateList(); + } + + [KSPAction("Jettison")] + public void AGJettsion(KSPActionParam param) + { + Jettison(); + } + + void ParseWeaponClass() + { + missileType = missileType.ToLower(); + if (missileType == "bomb") + { + weaponClass = WeaponClasses.Bomb; + } + else if (missileType == "torpedo" || missileType == "depthcharge") + { + weaponClass = WeaponClasses.SLW; + } + else + { + weaponClass = WeaponClasses.Missile; + } + } + + public override void OnStart(StartState state) + { + //base.OnStart(state); + ParseWeaponClass(); + + if (shortName == string.Empty) + { + shortName = part.partInfo.title; + } + + gaplessEmitters = new List(); + pEmitters = new List(); + boostEmitters = new List(); + boostGaplessEmitters = new List(); + + Fields["maxOffBoresight"].guiActive = false; + Fields["maxOffBoresight"].guiActiveEditor = false; + Fields["maxStaticLaunchRange"].guiActive = false; + Fields["maxStaticLaunchRange"].guiActiveEditor = false; + Fields["minStaticLaunchRange"].guiActive = false; + Fields["minStaticLaunchRange"].guiActiveEditor = false; + + if (isTimed) + { + Fields["detonationTime"].guiActive = true; + Fields["detonationTime"].guiActiveEditor = true; + } + else + { + Fields["detonationTime"].guiActive = false; + Fields["detonationTime"].guiActiveEditor = false; + } + + ParseModes(); + // extension for feature_engagementenvelope + InitializeEngagementRange(minStaticLaunchRange, maxStaticLaunchRange); + + List.Enumerator pEemitter = part.FindModelComponents().GetEnumerator(); + while (pEemitter.MoveNext()) + { + if (pEemitter.Current == null) continue; + EffectBehaviour.AddParticleEmitter(pEemitter.Current); + pEemitter.Current.emit = false; + } + pEemitter.Dispose(); + + if (HighLogic.LoadedSceneIsFlight) + { + //TODO: Backward compatibility wordaround + if (part.FindModuleImplementing() == null) + { + FromBlastPowerToTNTMass(); + } + else + { + //New Explosive module + DisablingExplosives(part); + } + + MissileReferenceTransform = part.FindModelTransform("missileTransform"); + if (!MissileReferenceTransform) + { + MissileReferenceTransform = part.partTransform; + } + + if (!string.IsNullOrEmpty(exhaustPrefabPath)) + { + IEnumerator t = part.FindModelTransforms("exhaustTransform").AsEnumerable().GetEnumerator(); + + while (t.MoveNext()) + { + if (t.Current == null) continue; + GameObject exhaustPrefab = (GameObject)Instantiate(GameDatabase.Instance.GetModel(exhaustPrefabPath)); + exhaustPrefab.SetActive(true); + IEnumerator emitter = exhaustPrefab.GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + emitter.Current.emit = false; + } + emitter.Dispose(); + exhaustPrefab.transform.parent = t.Current; + exhaustPrefab.transform.localPosition = Vector3.zero; + exhaustPrefab.transform.localRotation = Quaternion.identity; + } + t.Dispose(); + } + + if (!string.IsNullOrEmpty(boostExhaustPrefabPath) && !string.IsNullOrEmpty(boostExhaustTransformName)) + { + IEnumerator t = part.FindModelTransforms(boostExhaustTransformName).AsEnumerable().GetEnumerator(); + + while (t.MoveNext()) + { + if (t.Current == null) continue; + GameObject exhaustPrefab = (GameObject)Instantiate(GameDatabase.Instance.GetModel(boostExhaustPrefabPath)); + exhaustPrefab.SetActive(true); + IEnumerator emitter = exhaustPrefab.GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + emitter.Current.emit = false; + } + emitter.Dispose(); + exhaustPrefab.transform.parent = t.Current; + exhaustPrefab.transform.localPosition = Vector3.zero; + exhaustPrefab.transform.localRotation = Quaternion.identity; + } + t.Dispose(); + } + + boosters = new List(); + if (!string.IsNullOrEmpty(boostTransformName)) + { + IEnumerator t = part.FindModelTransforms(boostTransformName).AsEnumerable().GetEnumerator(); + while (t.MoveNext()) + { + if (t.Current == null) continue; + boosters.Add(t.Current.gameObject); + IEnumerator be = t.Current.GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (be.MoveNext()) + { + if (be.Current == null) continue; + if (be.Current.useWorldSpace) + { + if (be.Current.GetComponent()) continue; + BDAGaplessParticleEmitter ge = be.Current.gameObject.AddComponent(); + ge.part = part; + boostGaplessEmitters.Add(ge); + } + else + { + if (!boostEmitters.Contains(be.Current)) + { + boostEmitters.Add(be.Current); + } + EffectBehaviour.AddParticleEmitter(be.Current); + } + } + be.Dispose(); + } + t.Dispose(); + } + + IEnumerator pEmitter = part.partTransform.Find("model").GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (pEmitter.MoveNext()) + { + if (pEmitter.Current == null) continue; + if (pEmitter.Current.GetComponent() || boostEmitters.Contains(pEmitter.Current)) + { + continue; + } + + if (pEmitter.Current.useWorldSpace) + { + BDAGaplessParticleEmitter gaplessEmitter = pEmitter.Current.gameObject.AddComponent(); + gaplessEmitter.part = part; + gaplessEmitters.Add(gaplessEmitter); + } + else + { + if (pEmitter.Current.transform.name != boostTransformName) + { + pEmitters.Add(pEmitter.Current); + } + else + { + boostEmitters.Add(pEmitter.Current); + } + EffectBehaviour.AddParticleEmitter(pEmitter.Current); + } + } + pEmitter.Dispose(); + + cmTimer = Time.time; + + part.force_activate(); + + List.Enumerator pe = pEmitters.GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + if (hasRCS) + { + if (pe.Current.gameObject.name == "rcsUp") upRCS = pe.Current; + else if (pe.Current.gameObject.name == "rcsDown") downRCS = pe.Current; + else if (pe.Current.gameObject.name == "rcsLeft") leftRCS = pe.Current; + else if (pe.Current.gameObject.name == "rcsRight") rightRCS = pe.Current; + else if (pe.Current.gameObject.name == "rcsForward") forwardRCS = pe.Current; + } + + if (!pe.Current.gameObject.name.Contains("rcs") && !pe.Current.useWorldSpace) + { + pe.Current.sizeGrow = 99999; + } + } + pe.Dispose(); + + if (rotationTransformName != string.Empty) + { + rotationTransform = part.FindModelTransform(rotationTransformName); + } + + if (hasRCS) + { + SetupRCS(); + KillRCS(); + } + SetupAudio(); + } + + if (GuidanceMode != GuidanceModes.Cruise) + { + CruiseAltitudeRange(); + Fields["CruiseAltitude"].guiActive = false; + Fields["CruiseAltitude"].guiActiveEditor = false; + Fields["CruiseSpeed"].guiActive = false; + Fields["CruiseSpeed"].guiActiveEditor = false; + Events["CruiseAltitudeRange"].guiActive = false; + Events["CruiseAltitudeRange"].guiActiveEditor = false; + Fields["CruisePredictionTime"].guiActiveEditor = false; + } + + if (GuidanceMode != GuidanceModes.AGM) + { + Fields["maxAltitude"].guiActive = false; + Fields["maxAltitude"].guiActiveEditor = false; + } + if (GuidanceMode != GuidanceModes.AGMBallistic) + { + Fields["BallisticOverShootFactor"].guiActive = false; + Fields["BallisticOverShootFactor"].guiActiveEditor = false; + Fields["BallisticAngle"].guiActive = false; + Fields["BallisticAngle"].guiActiveEditor = false; + } + + if (part.partInfo.title.Contains("Bomb")) + { + Fields["dropTime"].guiActive = false; + Fields["dropTime"].guiActiveEditor = false; + } + + if (TargetingModeTerminal != TargetingModes.None) + { + Fields["terminalGuidanceShouldActivate"].guiName += terminalGuidanceType; + } + else + { + Fields["terminalGuidanceShouldActivate"].guiActive = false; + Fields["terminalGuidanceShouldActivate"].guiActiveEditor = false; + } + + if (deployAnimationName != "") + { + deployStates = Misc.Misc.SetUpAnimation(deployAnimationName, part); + } + else + { + deployedDrag = simpleDrag; + } + + SetInitialDetonationDistance(); + + // fill activeRadarLockTrackCurve with default values if not set by part config: + if ((TargetingMode == TargetingModes.Radar || TargetingModeTerminal == TargetingModes.Radar) && activeRadarRange > 0 && activeRadarLockTrackCurve.minTime == float.MaxValue) + { + activeRadarLockTrackCurve.Add(0f, 0f); + activeRadarLockTrackCurve.Add(activeRadarRange, RadarUtils.MISSILE_DEFAULT_LOCKABLE_RCS); // TODO: tune & balance constants! + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: OnStart missile " + shortName + ": setting default locktrackcurve with maxrange/minrcs: " + activeRadarLockTrackCurve.maxTime + "/" + RadarUtils.MISSILE_DEFAULT_LOCKABLE_RCS); + } + } + + /// + /// This method will convert the blastPower to a tnt mass equivalent + /// + private void FromBlastPowerToTNTMass() + { + blastPower = BlastPhysicsUtils.CalculateExplosiveMass(blastRadius); + } + + void OnCollisionEnter(Collision col) + { + base.CollisionEnter(col); + } + + void SetupAudio() + { + audioSource = gameObject.AddComponent(); + audioSource.minDistance = 1; + audioSource.maxDistance = 1000; + audioSource.loop = true; + audioSource.pitch = 1f; + audioSource.priority = 255; + audioSource.spatialBlend = 1; + + if (audioClipPath != string.Empty) + { + audioSource.clip = GameDatabase.Instance.GetAudioClip(audioClipPath); + } + + sfAudioSource = gameObject.AddComponent(); + sfAudioSource.minDistance = 1; + sfAudioSource.maxDistance = 2000; + sfAudioSource.dopplerLevel = 0; + sfAudioSource.priority = 230; + sfAudioSource.spatialBlend = 1; + + if (audioClipPath != string.Empty) + { + thrustAudio = GameDatabase.Instance.GetAudioClip(audioClipPath); + } + + if (boostClipPath != string.Empty) + { + boostAudio = GameDatabase.Instance.GetAudioClip(boostClipPath); + } + + UpdateVolume(); + BDArmorySetup.OnVolumeChange += UpdateVolume; + } + + void UpdateVolume() + { + if (audioSource) + { + audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + if (sfAudioSource) + { + sfAudioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + } + + void Update() + { + CheckDetonationState(); + if (HighLogic.LoadedSceneIsFlight) + { + if (weaponClass == WeaponClasses.SLW && FlightGlobals.getAltitudeAtPos(part.transform.position) > 0) //#710 + { + float a = (float)FlightGlobals.getGeeForceAtPosition(part.transform.position).magnitude; + float d = FlightGlobals.getAltitudeAtPos(part.transform.position); + dropTime = ((float)Math.Sqrt(a * (a + (8 * d))) - a) / (2 * a) - (Time.fixedDeltaTime * 1.5f); //quadratic equation for accel to find time from known force and vel + }// adjusts droptime to delay the MissileRoutine IEnum so torps won't start boosting until splashdown + } + } + + void OnDestroy() + { + BDArmorySetup.OnVolumeChange -= UpdateVolume; + GameEvents.onPartDie.Remove(PartDie); + } + + public override float GetBlastRadius() + { + if (part.FindModuleImplementing() != null) + { + return part.FindModuleImplementing().GetBlastRadius(); + } + else + { + return blastRadius; + } + } + + public override void FireMissile() + { + if (HasFired) return; + + SetupExplosive(this.part); + HasFired = true; + + Debug.Log("[BDArmory]: Missile Fired! " + vessel.vesselName); + + GameEvents.onPartDie.Add(PartDie); + BDATargetManager.FiredMissiles.Add(this); + + if (GetComponentInChildren()) + { + BDArmorySetup.numberOfParticleEmitters++; + } + + List.Enumerator wpm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (wpm.MoveNext()) + { + if (wpm.Current == null) continue; + Team = wpm.Current.Team; + break; + } + wpm.Dispose(); + + sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/deployClick")); + SourceVessel = vessel; + + //TARGETING + TargetPosition = transform.position + (transform.forward * 5000); //set initial target position so if no target update, missileBase will count a miss if it nears this point or is flying post-thrust + startDirection = transform.forward; + + SetLaserTargeting(); + SetAntiRadTargeting(); + + part.decouple(0); + part.force_activate(); + part.Unpack(); + vessel.situation = Vessel.Situations.FLYING; + part.rb.isKinematic = false; + part.bodyLiftMultiplier = 0; + part.dragModel = Part.DragModel.NONE; + + //add target info to vessel + AddTargetInfoToVessel(); + StartCoroutine(DecoupleRoutine()); + + vessel.vesselName = GetShortName(); + vessel.vesselType = VesselType.Probe; + + TimeFired = Time.time; + + //setting ref transform for navball + GameObject refObject = new GameObject(); + refObject.transform.rotation = Quaternion.LookRotation(-transform.up, transform.forward); + refObject.transform.parent = transform; + part.SetReferenceTransform(refObject.transform); + vessel.SetReferenceTransform(part); + vesselReferenceTransform = refObject.transform; + DetonationDistanceState = DetonationDistanceStates.NotSafe; + MissileState = MissileStates.Drop; + part.crashTolerance = 9999; //to combat stresses of launch, missle generate a lot of G Force + + StartCoroutine(MissileRoutine()); + } + + IEnumerator DecoupleRoutine() + { + yield return new WaitForFixedUpdate(); + + if (rndAngVel > 0) + { + part.rb.angularVelocity += UnityEngine.Random.insideUnitSphere.normalized * rndAngVel; + } + + if (decoupleForward) + { + part.rb.velocity += decoupleSpeed * part.transform.forward; + } + else + { + part.rb.velocity += decoupleSpeed * -part.transform.up; + } + } + + /// + /// Fires the missileBase on target vessel. Used by AI currently. + /// + /// V. + public void FireMissileOnTarget(Vessel v) + { + if (!HasFired) + { + legacyTargetVessel = v; + FireMissile(); + } + } + + void OnDisable() + { + if (TargetingMode == TargetingModes.AntiRad) + { + RadarWarningReceiver.OnRadarPing -= ReceiveRadarPing; + } + } + + public override void OnFixedUpdate() + { + debugString.Length = 0; + + if (HasFired && !HasExploded && part != null) + { + CheckDetonationDistance(); + + part.rb.isKinematic = false; + AntiSpin(); + + //simpleDrag + if (useSimpleDrag) + { + SimpleDrag(); + } + + //flybyaudio + float mCamDistanceSqr = (FlightCamera.fetch.mainCamera.transform.position - transform.position).sqrMagnitude; + float mCamRelVSqr = (float)(FlightGlobals.ActiveVessel.Velocity() - vessel.Velocity()).sqrMagnitude; + if (!hasPlayedFlyby + && FlightGlobals.ActiveVessel != vessel + && FlightGlobals.ActiveVessel != SourceVessel + && mCamDistanceSqr < 400 * 400 && mCamRelVSqr > 300 * 300 + && mCamRelVSqr < 800 * 800 + && Vector3.Angle(vessel.Velocity(), FlightGlobals.ActiveVessel.transform.position - transform.position) < 60) + { + sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/missileFlyby")); + hasPlayedFlyby = true; + } + + if (vessel.isActiveVessel) + { + audioSource.dopplerLevel = 0; + } + else + { + audioSource.dopplerLevel = 1f; + } + + if (TimeIndex > 0.5f) + { + if (torpedo) + { + if (vessel.altitude > 0) + { + part.crashTolerance = waterImpactTolerance; + } + else + { + part.crashTolerance = 1; + } + } + else + { + part.crashTolerance = 1; + } + } + + UpdateThrustForces(); + UpdateGuidance(); + //RaycastCollisions(); + + //Timed detonation + if (isTimed && TimeIndex > detonationTime) + { + Detonate(); + } + } + } + + private void CheckMiss() + { + float sqrDist = (float) ((TargetPosition + (TargetVelocity * Time.fixedDeltaTime)) - (vessel.CoM + (vessel.Velocity() * Time.fixedDeltaTime))).sqrMagnitude; + if (sqrDist < 160000 || MissileState == MissileStates.PostThrust) + { + checkMiss = true; + } + if (maxAltitude != 0f) + { + if (vessel.altitude >= maxAltitude) checkMiss = true; + } + + //kill guidance if missileBase has missed + if (!HasMissed && checkMiss) + { + bool noProgress = MissileState == MissileStates.PostThrust && (Vector3.Dot(vessel.Velocity() - TargetVelocity, TargetPosition - vessel.transform.position) < 0); + if (Vector3.Dot(TargetPosition - transform.position, transform.forward) < 0 || noProgress) + { + Debug.Log("[BDArmory]: Missile has missed!"); + + if (vessel.altitude >= maxAltitude && maxAltitude != 0f) + Debug.Log("[BDArmory]: CheckMiss trigged by MaxAltitude"); + + HasMissed = true; + guidanceActive = false; + + TargetMf = null; + + MissileLauncher launcher = this as MissileLauncher; + if (launcher != null) + { + if (launcher.hasRCS) launcher.KillRCS(); + } + + if (sqrDist < Mathf.Pow(GetBlastRadius() * 0.5f, 2)) part.Destroy(); + + isTimed = true; + detonationTime = TimeIndex + 1.5f; + return; + } + } + } + + + void UpdateGuidance() + { + if (guidanceActive) + { + if (TargetingMode == TargetingModes.Heat) + { + UpdateHeatTarget(); + } + else if (TargetingMode == TargetingModes.Radar) + { + UpdateRadarTarget(); + } + else if (TargetingMode == TargetingModes.Laser) + { + UpdateLaserTarget(); + } + else if (TargetingMode == TargetingModes.Gps) + { + UpdateGPSTarget(); + } + else if (TargetingMode == TargetingModes.AntiRad) + { + UpdateAntiRadiationTarget(); + } + + UpdateTerminalGuidance(); + } + + if (MissileState != MissileStates.Idle && MissileState != MissileStates.Drop) //guidance + { + //guidance and attitude stabilisation scales to atmospheric density. //use part.atmDensity + float atmosMultiplier = Mathf.Clamp01(2.5f * (float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody)); + + if (vessel.srfSpeed < optimumAirspeed) + { + float optimumSpeedFactor = (float)vessel.srfSpeed / (2 * optimumAirspeed); + controlAuthority = Mathf.Clamp01(atmosMultiplier * (-Mathf.Abs(2 * optimumSpeedFactor - 1) + 1)); + } + else + { + controlAuthority = Mathf.Clamp01(atmosMultiplier); + } + + if (vacuumSteerable) + { + controlAuthority = 1; + } + + debugString.Append($"controlAuthority: {controlAuthority}"); + debugString.Append(Environment.NewLine); + + if (guidanceActive)// && timeIndex - dropTime > 0.5f) + { + WarnTarget(); + + if (legacyTargetVessel && legacyTargetVessel.loaded) + { + Vector3 targetCoMPos = legacyTargetVessel.CoM; + TargetPosition = targetCoMPos + legacyTargetVessel.Velocity() * Time.fixedDeltaTime; + } + + //increaseTurnRate after launch + float turnRateDPS = Mathf.Clamp(((TimeIndex - dropTime) / boostTime) * maxTurnRateDPS * 25f, 0, maxTurnRateDPS); + if (!hasRCS) + { + turnRateDPS *= controlAuthority; + } + + //decrease turn rate after thrust cuts out + if (TimeIndex > dropTime + boostTime + cruiseTime) + { + var clampedTurnRate = Mathf.Clamp(maxTurnRateDPS - ((TimeIndex - dropTime - boostTime - cruiseTime) * 0.45f), + 1, maxTurnRateDPS); + turnRateDPS = clampedTurnRate; + + if (!vacuumSteerable) + { + turnRateDPS *= atmosMultiplier; + } + + if (hasRCS) + { + turnRateDPS = 0; + } + } + + if (hasRCS) + { + if (turnRateDPS > 0) + { + DoRCS(); + } + else + { + KillRCS(); + } + } + debugTurnRate = turnRateDPS; + + finalMaxTorque = Mathf.Clamp((TimeIndex - dropTime) * torqueRampUp, 0, maxTorque); //ramp up torque + + if (GuidanceMode == GuidanceModes.AAMLead) + { + AAMGuidance(); + } + else if (GuidanceMode == GuidanceModes.AGM) + { + AGMGuidance(); + } + else if (GuidanceMode == GuidanceModes.AGMBallistic) + { + AGMBallisticGuidance(); + } + else if (GuidanceMode == GuidanceModes.BeamRiding) + { + BeamRideGuidance(); + } + else if (GuidanceMode == GuidanceModes.RCS) + { + part.transform.rotation = Quaternion.RotateTowards(part.transform.rotation, Quaternion.LookRotation(TargetPosition - part.transform.position, part.transform.up), turnRateDPS * Time.fixedDeltaTime); + } + else if (GuidanceMode == GuidanceModes.Cruise) + { + CruiseGuidance(); + } + else if (GuidanceMode == GuidanceModes.SLW) + { + SLWGuidance(); + } + + } + else + { + CheckMiss(); + TargetMf = null; + if (aero) + { + aeroTorque = MissileGuidance.DoAeroForces(this, transform.position + (20 * vessel.Velocity()), liftArea, .25f, aeroTorque, maxTorque, maxAoA); + } + } + + if (aero && aeroSteerDamping > 0) + { + part.rb.AddRelativeTorque(-aeroSteerDamping * part.transform.InverseTransformVector(part.rb.angularVelocity)); + } + + if (hasRCS && !guidanceActive) + { + KillRCS(); + } + } + } + + // feature_engagementenvelope: terminal guidance mode for cruise missiles + private void UpdateTerminalGuidance() + { + // check if guidance mode should be changed for terminal phase + float distanceSqr = (TargetPosition - transform.position).sqrMagnitude; + + if ((TargetingModeTerminal != TargetingModes.None) && (distanceSqr < terminalGuidanceDistance * terminalGuidanceDistance) && !terminalGuidanceActive && terminalGuidanceShouldActivate) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory][Terminal Guidance]: missile " + this.name + " updating targeting mode: " + terminalGuidanceType); + + TargetingMode = TargetingModeTerminal; + terminalGuidanceActive = true; + TargetAcquired = false; + + switch (TargetingModeTerminal) + { + case TargetingModes.Heat: + // get ground heat targets + heatTarget = BDATargetManager.GetHeatTarget(SourceVessel, vessel, new Ray(transform.position + (50 * GetForwardTransform()), TargetPosition - GetForwardTransform()), terminalGuidanceDistance, heatThreshold, true, SourceVessel.gameObject.GetComponent(), true); + if (heatTarget.exists) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory][Terminal Guidance]: Heat target acquired! Position: " + heatTarget.position + ", heatscore: " + heatTarget.signalStrength); + TargetAcquired = true; + TargetPosition = heatTarget.position + (heatTarget.velocity * Time.fixedDeltaTime); + TargetVelocity = heatTarget.velocity; + TargetAcceleration = heatTarget.acceleration; + lockFailTimer = 0; + targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(TargetPosition, vessel.mainBody); + } + else + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory][Terminal Guidance]: Missile heatseeker could not acquire a target lock."); + } + break; + + case TargetingModes.Radar: + + // pretend we have an active radar seeker for ground targets: + TargetSignatureData[] scannedTargets = new TargetSignatureData[5]; + TargetSignatureData.ResetTSDArray(ref scannedTargets); + Ray ray = new Ray(transform.position, TargetPosition - GetForwardTransform()); + + //RadarUtils.UpdateRadarLock(ray, maxOffBoresight, activeRadarMinThresh, ref scannedTargets, 0.4f, true, RadarWarningReceiver.RWRThreatTypes.MissileLock, true); + RadarUtils.RadarUpdateMissileLock(ray, maxOffBoresight, ref scannedTargets, 0.4f, this); + float sqrThresh = Mathf.Pow(terminalGuidanceDistance * 1.5f, 2); + + //float smallestAngle = maxOffBoresight; + TargetSignatureData lockedTarget = TargetSignatureData.noTarget; + + for (int i = 0; i < scannedTargets.Length; i++) + { + if (scannedTargets[i].exists && (scannedTargets[i].predictedPosition - TargetPosition).sqrMagnitude < sqrThresh) + { + //re-check engagement envelope, only lock appropriate targets + if (CheckTargetEngagementEnvelope(scannedTargets[i].targetInfo)) + { + lockedTarget = scannedTargets[i]; + ActiveRadar = true; + } + } + } + + if (lockedTarget.exists) + { + radarTarget = lockedTarget; + TargetAcquired = true; + TargetPosition = radarTarget.predictedPositionWithChaffFactor; + TargetVelocity = radarTarget.velocity; + TargetAcceleration = radarTarget.acceleration; + targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(TargetPosition, vessel.mainBody); + + if (weaponClass == WeaponClasses.SLW) + RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), 45, RadarWarningReceiver.RWRThreatTypes.Torpedo, 2f); + else + RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), 45, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); + + Debug.Log("[BDArmory][Terminal Guidance]: Pitbull! Radar missileBase has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0") + " - target: " + radarTarget.vessel.name); + } + else + { + TargetAcquired = true; + TargetPosition = VectorUtils.GetWorldSurfacePostion(UpdateGPSTarget(), vessel.mainBody); //putting back the GPS target if no radar target found + TargetVelocity = Vector3.zero; + TargetAcceleration = Vector3.zero; + targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(TargetPosition, vessel.mainBody); + Debug.Log("[BDArmory][Terminal Guidance]: Missile radar could not acquire a target lock - Defaulting to GPS Target"); + } + break; + + case TargetingModes.Laser: + // not very useful, currently unsupported! + break; + + case TargetingModes.Gps: + // from gps to gps -> no actions need to be done! + break; + + case TargetingModes.AntiRad: + TargetAcquired = true; + SetAntiRadTargeting(); //should then already work automatically via OnReceiveRadarPing + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory][Terminal Guidance]: Antiradiation mode set! Waiting for radar signals..."); + break; + } + } + } + + void UpdateThrustForces() + { + if (MissileState == MissileStates.PostThrust) return; + if (weaponClass == WeaponClasses.SLW && FlightGlobals.getAltitudeAtPos(part.transform.position) > 0) return; //#710, no torp thrust out of water + if (currentThrust * Throttle > 0) + { + debugString.Append("Missile thrust=" + currentThrust * Throttle); + debugString.Append(Environment.NewLine); + + part.rb.AddRelativeForce(currentThrust * Throttle * Vector3.forward); + } + } + + IEnumerator MissileRoutine() + { + MissileState = MissileStates.Drop; + StartCoroutine(AnimRoutine()); + yield return new WaitForSeconds(dropTime); + yield return StartCoroutine(BoostRoutine()); + yield return new WaitForSeconds(cruiseDelay); + yield return StartCoroutine(CruiseRoutine()); + } + + IEnumerator AnimRoutine() + { + yield return new WaitForSeconds(deployTime); + + if (!string.IsNullOrEmpty(deployAnimationName)) + { + deployed = true; + IEnumerator anim = deployStates.AsEnumerable().GetEnumerator(); + while (anim.MoveNext()) + { + if (anim.Current == null) continue; + anim.Current.speed = 1; + } + anim.Dispose(); + } + } + + IEnumerator BoostRoutine() + { + StartBoost(); + float boostStartTime = Time.time; + while (Time.time - boostStartTime < boostTime) + { + //light, sound & particle fx + //sound + if (!BDArmorySetup.GameIsPaused) + { + if (!audioSource.isPlaying) + { + audioSource.Play(); + } + } + else if (audioSource.isPlaying) + { + audioSource.Stop(); + } + + //particleFx + List.Enumerator emitter = boostEmitters.GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + if (!hasRCS) + { + emitter.Current.sizeGrow = Mathf.Lerp(emitter.Current.sizeGrow, 0, 20 * Time.deltaTime); + } + } + emitter.Dispose(); + + List.Enumerator gpe = boostGaplessEmitters.GetEnumerator(); + while (gpe.MoveNext()) + { + if (gpe.Current == null) continue; + if ((!vessel.InVacuum() && Throttle > 0) && weaponClass != WeaponClasses.SLW || (weaponClass == WeaponClasses.SLW && FlightGlobals.getAltitudeAtPos(part.transform.position) < 0 )) //#710 + { + gpe.Current.emit = true; + gpe.Current.pEmitter.worldVelocity = 2 * ParticleTurbulence.flareTurbulence; + } + else + { + gpe.Current.emit = false; + } + } + gpe.Dispose(); + + //thrust + if (spoolEngine) + { + currentThrust = Mathf.MoveTowards(currentThrust, thrust, thrust / 10); + } + + yield return null; + } + EndBoost(); + } + + void StartBoost() + { + MissileState = MissileStates.Boost; + + if (boostAudio) + { + audioSource.clip = boostAudio; + } + else if (thrustAudio) + { + audioSource.clip = thrustAudio; + } + + IEnumerator light = gameObject.GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (light.MoveNext()) + { + if (light.Current == null) continue; + light.Current.intensity = 1.5f; + } + light.Dispose(); + + if (!spoolEngine) + { + currentThrust = thrust; + } + + if (string.IsNullOrEmpty(boostTransformName)) + { + boostEmitters = pEmitters; + boostGaplessEmitters = gaplessEmitters; + } + + List.Enumerator emitter = boostEmitters.GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + emitter.Current.emit = true; + } + emitter.Dispose(); + + if (hasRCS) + { + forwardRCS.emit = true; + } + + if (!(thrust > 0)) return; + sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/launch")); + RadarWarningReceiver.WarnMissileLaunch(transform.position, transform.forward); + } + + void EndBoost() + { + List.Enumerator emitter = boostEmitters.GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + emitter.Current.emit = false; + } + emitter.Dispose(); + + List.Enumerator gEmitter = boostGaplessEmitters.GetEnumerator(); + while (gEmitter.MoveNext()) + { + if (gEmitter.Current == null) continue; + gEmitter.Current.emit = false; + } + gEmitter.Dispose(); + + if (decoupleBoosters) + { + part.mass -= boosterMass; + List.Enumerator booster = boosters.GetEnumerator(); + while (booster.MoveNext()) + { + if (booster.Current == null) continue; + booster.Current.AddComponent().DecoupleBooster(part.rb.velocity, boosterDecoupleSpeed); + } + booster.Dispose(); + } + + if (cruiseDelay > 0) + { + currentThrust = 0; + } + } + + IEnumerator CruiseRoutine() + { + StartCruise(); + float cruiseStartTime = Time.time; + while (Time.time - cruiseStartTime < cruiseTime) + { + if (!BDArmorySetup.GameIsPaused) + { + if (!audioSource.isPlaying || audioSource.clip != thrustAudio) + { + audioSource.clip = thrustAudio; + audioSource.Play(); + } + } + else if (audioSource.isPlaying) + { + audioSource.Stop(); + } + audioSource.volume = Throttle; + + //particleFx + List.Enumerator emitter = pEmitters.GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + if (!hasRCS) + { + emitter.Current.sizeGrow = Mathf.Lerp(emitter.Current.sizeGrow, 0, 20 * Time.deltaTime); + } + + emitter.Current.maxSize = Mathf.Clamp01(Throttle / Mathf.Clamp((float)vessel.atmDensity, 0.2f, 1f)); + if (weaponClass != WeaponClasses.SLW || (weaponClass == WeaponClasses.SLW && FlightGlobals.getAltitudeAtPos(part.transform.position) < 0)) //#710 + { + emitter.Current.emit = true; + } + else + { + emitter.Current.emit = false; // #710, shut down thrust FX for torps out of water + } + } + emitter.Dispose(); + + List.Enumerator gpe = gaplessEmitters.GetEnumerator(); + while (gpe.MoveNext()) + { + if (gpe.Current == null) continue; + if (weaponClass != WeaponClasses.SLW || (weaponClass == WeaponClasses.SLW && FlightGlobals.getAltitudeAtPos(part.transform.position) < 0)) //#710 + { + gpe.Current.pEmitter.maxSize = Mathf.Clamp01(Throttle / Mathf.Clamp((float)vessel.atmDensity, 0.2f, 1f)); + gpe.Current.emit = true; + gpe.Current.pEmitter.worldVelocity = 2 * ParticleTurbulence.flareTurbulence; + } + else + { + gpe.Current.emit = false; + } + } + gpe.Dispose(); + + if (spoolEngine) + { + currentThrust = Mathf.MoveTowards(currentThrust, cruiseThrust, cruiseThrust / 10); + } + yield return null; + } + EndCruise(); + } + + void StartCruise() + { + MissileState = MissileStates.Cruise; + + if (thrustAudio) + { + audioSource.clip = thrustAudio; + } + + currentThrust = spoolEngine ? 0 : cruiseThrust; + + List.Enumerator pEmitter = pEmitters.GetEnumerator(); + while (pEmitter.MoveNext()) + { + if (pEmitter.Current == null) continue; + EffectBehaviour.AddParticleEmitter(pEmitter.Current); + pEmitter.Current.emit = true; + } + pEmitter.Dispose(); + + List.Enumerator gEmitter = gaplessEmitters.GetEnumerator(); + while (gEmitter.MoveNext()) + { + if (gEmitter.Current == null) continue; + EffectBehaviour.AddParticleEmitter(gEmitter.Current.pEmitter); + gEmitter.Current.emit = true; + } + gEmitter.Dispose(); + + if (!hasRCS) return; + forwardRCS.emit = false; + audioSource.Stop(); + } + + void EndCruise() + { + MissileState = MissileStates.PostThrust; + + IEnumerator light = gameObject.GetComponentsInChildren().AsEnumerable().GetEnumerator(); + while (light.MoveNext()) + { + if (light.Current == null) continue; + light.Current.intensity = 0; + } + light.Dispose(); + + StartCoroutine(FadeOutAudio()); + StartCoroutine(FadeOutEmitters()); + } + + IEnumerator FadeOutAudio() + { + if (thrustAudio && audioSource.isPlaying) + { + while (audioSource.volume > 0 || audioSource.pitch > 0) + { + audioSource.volume = Mathf.Lerp(audioSource.volume, 0, 5 * Time.deltaTime); + audioSource.pitch = Mathf.Lerp(audioSource.pitch, 0, 5 * Time.deltaTime); + yield return null; + } + } + } + + IEnumerator FadeOutEmitters() + { + float fadeoutStartTime = Time.time; + while (Time.time - fadeoutStartTime < 5) + { + List.Enumerator pe = pEmitters.GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + pe.Current.maxEmission = Mathf.FloorToInt(pe.Current.maxEmission * 0.8f); + pe.Current.minEmission = Mathf.FloorToInt(pe.Current.minEmission * 0.8f); + } + pe.Dispose(); + + List.Enumerator gpe = gaplessEmitters.GetEnumerator(); + while (gpe.MoveNext()) + { + if (gpe.Current == null) continue; + gpe.Current.pEmitter.maxSize = Mathf.MoveTowards(gpe.Current.pEmitter.maxSize, 0, 0.005f); + gpe.Current.pEmitter.minSize = Mathf.MoveTowards(gpe.Current.pEmitter.minSize, 0, 0.008f); + gpe.Current.pEmitter.worldVelocity = ParticleTurbulence.Turbulence; + } + gpe.Dispose(); + yield return new WaitForFixedUpdate(); + } + + List.Enumerator pe2 = pEmitters.GetEnumerator(); + while (pe2.MoveNext()) + { + if (pe2.Current == null) continue; + pe2.Current.emit = false; + } + pe2.Dispose(); + + List.Enumerator gpe2 = gaplessEmitters.GetEnumerator(); + while (gpe2.MoveNext()) + { + if (gpe2.Current == null) continue; + gpe2.Current.emit = false; + } + gpe2.Dispose(); + } + + [KSPField] + public float beamCorrectionFactor; + + [KSPField] + public float beamCorrectionDamping; + + Ray previousBeam; + + void BeamRideGuidance() + { + if (!targetingPod) + { + guidanceActive = false; + return; + } + + if (RadarUtils.TerrainCheck(targetingPod.cameraParentTransform.position, transform.position)) + { + guidanceActive = false; + return; + } + Ray laserBeam = new Ray(targetingPod.cameraParentTransform.position + (targetingPod.vessel.Velocity() * Time.fixedDeltaTime), targetingPod.targetPointPosition - targetingPod.cameraParentTransform.position); + Vector3 target = MissileGuidance.GetBeamRideTarget(laserBeam, part.transform.position, vessel.Velocity(), beamCorrectionFactor, beamCorrectionDamping, (TimeIndex > 0.25f ? previousBeam : laserBeam)); + previousBeam = laserBeam; + DrawDebugLine(part.transform.position, target); + DoAero(target); + } + + void CruiseGuidance() + { + if (this._guidance == null) + { + this._guidance = new CruiseGuidance(this); + } + + Vector3 cruiseTarget = Vector3.zero; + + cruiseTarget = this._guidance.GetDirection(this,TargetPosition); + + Vector3 upDirection = VectorUtils.GetUpDirection(transform.position); + + //axial rotation + if (rotationTransform) + { + Quaternion originalRotation = transform.rotation; + Quaternion originalRTrotation = rotationTransform.rotation; + transform.rotation = Quaternion.LookRotation(transform.forward, upDirection); + rotationTransform.rotation = originalRTrotation; + Vector3 lookUpDirection = Vector3.ProjectOnPlane(cruiseTarget - transform.position, transform.forward) * 100; + lookUpDirection = transform.InverseTransformPoint(lookUpDirection + transform.position); + + lookUpDirection = new Vector3(lookUpDirection.x, 0, 0); + lookUpDirection += 10 * Vector3.up; + + rotationTransform.localRotation = Quaternion.Lerp(rotationTransform.localRotation, Quaternion.LookRotation(Vector3.forward, lookUpDirection), 0.04f); + Quaternion finalRotation = rotationTransform.rotation; + transform.rotation = originalRotation; + rotationTransform.rotation = finalRotation; + + vesselReferenceTransform.rotation = Quaternion.LookRotation(-rotationTransform.up, rotationTransform.forward); + } + DoAero(cruiseTarget); + CheckMiss(); + } + + void AAMGuidance() + { + Vector3 aamTarget; + if (TargetAcquired) + { + DrawDebugLine(transform.position + (part.rb.velocity * Time.fixedDeltaTime), TargetPosition); + float timeToImpact; + aamTarget = MissileGuidance.GetAirToAirTarget(TargetPosition, TargetVelocity, TargetAcceleration, vessel, out timeToImpact, optimumAirspeed); + TimeToImpact = timeToImpact; + if (Vector3.Angle(aamTarget - transform.position, transform.forward) > maxOffBoresight * 0.75f) + { + aamTarget = TargetPosition; + } + + //proxy detonation + if (proxyDetonate && ((TargetPosition + (TargetVelocity * Time.fixedDeltaTime)) - (transform.position)).sqrMagnitude < Mathf.Pow(GetBlastRadius() * 0.5f, 2)) + { + part.Destroy(); + } + } + else + { + aamTarget = transform.position + (20 * vessel.Velocity().normalized); + } + + if (TimeIndex > dropTime + 0.25f) + { + DoAero(aamTarget); + CheckMiss(); + } + + } + + void AGMGuidance() + { + if (TargetingMode != TargetingModes.Gps) + { + if (TargetAcquired) + { + //lose lock if seeker reaches gimbal limit + float targetViewAngle = Vector3.Angle(transform.forward, TargetPosition - transform.position); + + if (targetViewAngle > maxOffBoresight) + { + Debug.Log("[BDArmory]: AGM Missile guidance failed - target out of view"); + guidanceActive = false; + } + CheckMiss(); + } + else + { + if (TargetingMode == TargetingModes.Laser) + { + //keep going straight until found laser point + TargetPosition = laserStartPosition + (20000 * startDirection); + } + } + } + + Vector3 agmTarget = MissileGuidance.GetAirToGroundTarget(TargetPosition, vessel, agmDescentRatio); + DoAero(agmTarget); + } + + void SLWGuidance() + { + Vector3 SLWTarget; + if (TargetAcquired) + { + DrawDebugLine(transform.position + (part.rb.velocity * Time.fixedDeltaTime), TargetPosition); + float timeToImpact; + SLWTarget = MissileGuidance.GetAirToAirTarget(TargetPosition, TargetVelocity, TargetAcceleration, vessel, out timeToImpact, optimumAirspeed); + TimeToImpact = timeToImpact; + if (Vector3.Angle(SLWTarget - transform.position, transform.forward) > maxOffBoresight * 0.75f) + { + SLWTarget = TargetPosition; + } + + //proxy detonation + if (proxyDetonate && ((TargetPosition + (TargetVelocity * Time.fixedDeltaTime)) - (transform.position)).sqrMagnitude < Mathf.Pow(GetBlastRadius() * 0.5f, 2)) + { + part.Destroy(); + } + } + else + { + SLWTarget = transform.position + (20 * vessel.Velocity().normalized); + } + + if (TimeIndex > dropTime + 0.25f) + { + DoAero(SLWTarget); + } + + if (SLWTarget.y > 0f) SLWTarget.y = getSWLWOffset; + + CheckMiss(); + + } + + void DoAero(Vector3 targetPosition) + { + aeroTorque = MissileGuidance.DoAeroForces(this, targetPosition, liftArea, controlAuthority * steerMult, aeroTorque, finalMaxTorque, maxAoA); + } + + void AGMBallisticGuidance() + { + DoAero(CalculateAGMBallisticGuidance(this, TargetPosition)); + } + + public override void Detonate() + { + if (HasExploded || !HasFired) return; + + Debug.Log("[BDArmory]: Detonate Triggered"); + + BDArmorySetup.numberOfParticleEmitters--; + HasExploded = true; + + if (legacyTargetVessel != null) + { + List.Enumerator wpm = legacyTargetVessel.FindPartModulesImplementing().GetEnumerator(); + while (wpm.MoveNext()) + { + if (wpm.Current == null) continue; + wpm.Current.missileIsIncoming = false; + } + wpm.Dispose(); + } + + if (SourceVessel == null) SourceVessel = vessel; + + if (part.FindModuleImplementing() != null) + { + part.FindModuleImplementing().DetonateIfPossible(); + } + else //TODO: Remove this backguard compatibility + { + Vector3 position = transform.position;//+rigidbody.velocity*Time.fixedDeltaTime; + + ExplosionFx.CreateExplosion(position, blastPower, explModelPath, explSoundPath, true, 0, part); + } + + List.Enumerator e = gaplessEmitters.GetEnumerator(); + while (e.MoveNext()) + { + if (e.Current == null) continue; + e.Current.gameObject.AddComponent(); + e.Current.transform.parent = null; + if (e.Current.GetComponent()) + { + e.Current.GetComponent().enabled = false; + } + } + e.Dispose(); + + if (part != null) + { + part.Destroy(); + part.explode(); + } + } + + public override Vector3 GetForwardTransform() + { + return MissileReferenceTransform.forward; + } + + protected override void PartDie(Part p) + { + if (p == part) + { + Detonate(); + BDATargetManager.FiredMissiles.Remove(this); + GameEvents.onPartDie.Remove(PartDie); + } + } + + public static bool CheckIfMissile(Part p) + { + return p.GetComponent(); + } + + void WarnTarget() + { + if (legacyTargetVessel == null) return; + if (legacyTargetVessel == null) return; + List.Enumerator wpm = legacyTargetVessel.FindPartModulesImplementing().GetEnumerator(); + while (wpm.MoveNext()) + { + if (wpm.Current == null) continue; + wpm.Current.MissileWarning(Vector3.Distance(transform.position, legacyTargetVessel.transform.position), this); + break; + } + wpm.Dispose(); + } + + void SetupRCS() + { + rcsFiredTimes = new float[] { 0, 0, 0, 0 }; + rcsTransforms = new KSPParticleEmitter[] { upRCS, leftRCS, rightRCS, downRCS }; + } + + void DoRCS() + { + Vector3 relV = TargetVelocity - vessel.obt_velocity; + + for (int i = 0; i < 4; i++) + { + //float giveThrust = Mathf.Clamp(-localRelV.z, 0, rcsThrust); + float giveThrust = Mathf.Clamp(Vector3.Project(relV, rcsTransforms[i].transform.forward).magnitude * -Mathf.Sign(Vector3.Dot(rcsTransforms[i].transform.forward, relV)), 0, rcsThrust); + part.rb.AddForce(-giveThrust * rcsTransforms[i].transform.forward); + + if (giveThrust > rcsRVelThreshold) + { + rcsAudioMinInterval = UnityEngine.Random.Range(0.15f, 0.25f); + if (Time.time - rcsFiredTimes[i] > rcsAudioMinInterval) + { + sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/popThrust")); + rcsTransforms[i].emit = true; + rcsFiredTimes[i] = Time.time; + } + } + else + { + rcsTransforms[i].emit = false; + } + + //turn off emit + if (Time.time - rcsFiredTimes[i] > rcsAudioMinInterval * 0.75f) + { + rcsTransforms[i].emit = false; + } + } + } + + public void KillRCS() + { + upRCS.emit = false; + EffectBehaviour.RemoveParticleEmitter(upRCS); + downRCS.emit = false; + EffectBehaviour.RemoveParticleEmitter(downRCS); + leftRCS.emit = false; + EffectBehaviour.RemoveParticleEmitter(leftRCS); + rightRCS.emit = false; + EffectBehaviour.RemoveParticleEmitter(rightRCS); + } + + void OnGUI() + { + if (HighLogic.LoadedSceneIsFlight) + { + try + { + drawLabels(); + } + catch (Exception) + { } + } + } + + void AntiSpin() + { + part.rb.angularDrag = 0; + part.angularDrag = 0; + Vector3 spin = Vector3.Project(part.rb.angularVelocity, part.rb.transform.forward);// * 8 * Time.fixedDeltaTime; + part.rb.angularVelocity -= spin; + //rigidbody.maxAngularVelocity = 7; + + if (guidanceActive) + { + part.rb.angularVelocity -= 0.6f * part.rb.angularVelocity; + } + else + { + part.rb.angularVelocity -= 0.02f * part.rb.angularVelocity; + } + } + + void SimpleDrag() + { + part.dragModel = Part.DragModel.NONE; + //float simSpeedSquared = (float)vessel.Velocity.sqrMagnitude; + float simSpeedSquared = (part.rb.GetPointVelocity(part.transform.TransformPoint(simpleCoD)) + (Vector3)Krakensbane.GetFrameVelocity()).sqrMagnitude; + Vector3 currPos = transform.position; + float drag = deployed ? deployedDrag : simpleDrag; + float dragMagnitude = (0.008f * part.rb.mass) * drag * 0.5f * simSpeedSquared * (float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody); + Vector3 dragForce = dragMagnitude * vessel.Velocity().normalized; + part.rb.AddForceAtPosition(-dragForce, transform.TransformPoint(simpleCoD)); + + Vector3 torqueAxis = -Vector3.Cross(vessel.Velocity(), part.transform.forward).normalized; + float AoA = Vector3.Angle(part.transform.forward, vessel.Velocity()); + AoA /= 20; + part.rb.AddTorque(AoA * simpleStableTorque * dragMagnitude * torqueAxis); + } + + void ParseModes() + { + homingType = homingType.ToLower(); + switch (homingType) + { + case "aam": + GuidanceMode = GuidanceModes.AAMLead; + break; + + case "aamlead": + GuidanceMode = GuidanceModes.AAMLead; + break; + + case "aampure": + GuidanceMode = GuidanceModes.AAMPure; + break; + + case "agm": + GuidanceMode = GuidanceModes.AGM; + break; + + case "agmballistic": + GuidanceMode = GuidanceModes.AGMBallistic; + break; + + case "cruise": + GuidanceMode = GuidanceModes.Cruise; + break; + + case "sts": + GuidanceMode = GuidanceModes.STS; + break; + + case "rcs": + GuidanceMode = GuidanceModes.RCS; + break; + + case "beamriding": + GuidanceMode = GuidanceModes.BeamRiding; + break; + + case "slw": + GuidanceMode = GuidanceModes.SLW; + break; + + default: + GuidanceMode = GuidanceModes.None; + break; + } + + targetingType = targetingType.ToLower(); + switch (targetingType) + { + case "radar": + TargetingMode = TargetingModes.Radar; + break; + + case "heat": + TargetingMode = TargetingModes.Heat; + break; + + case "laser": + TargetingMode = TargetingModes.Laser; + break; + + case "gps": + TargetingMode = TargetingModes.Gps; + maxOffBoresight = 360; + break; + + case "antirad": + TargetingMode = TargetingModes.AntiRad; + break; + + default: + TargetingMode = TargetingModes.None; + break; + } + + terminalGuidanceType = terminalGuidanceType.ToLower(); + switch (terminalGuidanceType) + { + case "radar": + TargetingModeTerminal = TargetingModes.Radar; + break; + + case "heat": + TargetingModeTerminal = TargetingModes.Heat; + break; + + case "laser": + TargetingModeTerminal = TargetingModes.Laser; + break; + + case "gps": + TargetingModeTerminal = TargetingModes.Gps; + maxOffBoresight = 360; + break; + + case "antirad": + TargetingModeTerminal = TargetingModes.AntiRad; + break; + + default: + TargetingModeTerminal = TargetingModes.None; + break; + } + } + + private string GetBrevityCode() + { + //torpedo: determine subtype + if (missileType.ToLower() == "torpedo") + { + if ((TargetingMode == TargetingModes.Radar) && (activeRadarRange > 0)) + return "Active Sonar"; + + if ((TargetingMode == TargetingModes.Radar) && (activeRadarRange <= 0)) + return "Passive Sonar"; + + if ((TargetingMode == TargetingModes.Laser) || (TargetingMode == TargetingModes.Gps)) + return "Optical/wireguided"; + + if ((TargetingMode == TargetingModes.Heat)) + return "Heat guided"; + + if ((TargetingMode == TargetingModes.None)) + return "Unguided"; + } + + if (missileType.ToLower() == "bomb") + { + if ((TargetingMode == TargetingModes.Laser) || (TargetingMode == TargetingModes.Gps)) + return "JDAM"; + + if ((TargetingMode == TargetingModes.None)) + return "Unguided"; + } + + //else: missiles: + + if (TargetingMode == TargetingModes.Radar) + { + //radar: determine subtype + if (activeRadarRange <= 0) + return "SARH"; + if (activeRadarRange > 0 && activeRadarRange < maxStaticLaunchRange) + return "Mixed SARH/F&F"; + if (activeRadarRange >= maxStaticLaunchRange) + return "Fire&Forget"; + } + + if (TargetingMode == TargetingModes.AntiRad) + return "Fire&Forget"; + + if (TargetingMode == TargetingModes.Heat) + return "Fire&Forget"; + + if (TargetingMode == TargetingModes.Laser) + return "SALH"; + + if (TargetingMode == TargetingModes.Gps) + { + return TargetingModeTerminal != TargetingModes.None ? "GPS/Terminal" : "GPS"; + } + + // default: + return "Unguided"; + } + + // RMB info in editor + public override string GetInfo() + { + ParseModes(); + + StringBuilder output = new StringBuilder(); + output.AppendLine($"{missileType.ToUpper()} - {GetBrevityCode()}"); + output.Append(Environment.NewLine); + output.AppendLine($"Targeting Type: {targetingType.ToLower()}"); + output.AppendLine($"Guidance Mode: {homingType.ToLower()}"); + if (missileRadarCrossSection != RadarUtils.RCS_MISSILES) + { + output.AppendLine($"Detectable cross section: {missileRadarCrossSection} m^2"); + } + output.AppendLine($"Min Range: {minStaticLaunchRange} m"); + output.AppendLine($"Max Range: {maxStaticLaunchRange} m"); + + if (TargetingMode == TargetingModes.Radar) + { + if (activeRadarRange > 0) + { + output.AppendLine($"Active Radar Range: {activeRadarRange} m"); + if (activeRadarLockTrackCurve.maxTime > 0) + output.AppendLine($"- Lock/Track: {activeRadarLockTrackCurve.Evaluate(activeRadarLockTrackCurve.maxTime)} m^2 @ {activeRadarLockTrackCurve.maxTime} km"); + else + output.AppendLine($"- Lock/Track: {RadarUtils.MISSILE_DEFAULT_LOCKABLE_RCS} m^2 @ {activeRadarRange / 1000} km"); + output.AppendLine($"- LOAL: {radarLOAL}"); + } + output.AppendLine($"Max Offborsight: {maxOffBoresight}"); + output.AppendLine($"Locked FOV: {lockedSensorFOV}"); + } + + if (TargetingMode == TargetingModes.Heat) + { + output.AppendLine($"All Aspect: {allAspect}"); + output.AppendLine($"Min Heat threshold: {heatThreshold}"); + output.AppendLine($"Max Offborsight: {maxOffBoresight}"); + output.AppendLine($"Locked FOV: {lockedSensorFOV}"); + } + + if (TargetingMode == TargetingModes.Gps) + { + output.AppendLine($"Terminal Maneuvering: {terminalManeuvering}"); + if (terminalGuidanceType != "") + { + output.AppendLine($"Terminal guidance: {terminalGuidanceType} @ distance: {terminalGuidanceDistance} m"); + + if (TargetingModeTerminal == TargetingModes.Radar) + { + output.AppendLine($"Active Radar Range: {activeRadarRange} m"); + if (activeRadarLockTrackCurve.maxTime > 0) + output.AppendLine($"- Lock/Track: {activeRadarLockTrackCurve.Evaluate(activeRadarLockTrackCurve.maxTime)} m^2 @ {activeRadarLockTrackCurve.maxTime} km"); + else + output.AppendLine($"- Lock/Track: {RadarUtils.MISSILE_DEFAULT_LOCKABLE_RCS} m^2 @ {activeRadarRange / 1000} km"); + output.AppendLine($"- LOAL: {radarLOAL}"); + output.AppendLine($"Max Offborsight: {maxOffBoresight}"); + output.AppendLine($"Locked FOV: {lockedSensorFOV}"); + } + + if (TargetingModeTerminal == TargetingModes.Heat) + { + output.AppendLine($"All Aspect: {allAspect}"); + output.AppendLine($"Min Heat threshold: {heatThreshold}"); + output.AppendLine($"Max Offborsight: {maxOffBoresight}"); + output.AppendLine($"Locked FOV: {lockedSensorFOV}"); + } + } + } + + IEnumerator partModules = part.Modules.GetEnumerator(); + output.AppendLine($"Warhead:"); + while (partModules.MoveNext()) + { + if (partModules.Current == null) continue; + if (partModules.Current.moduleName != "BDExplosivePart") continue; + float tntMass = ((BDExplosivePart)partModules.Current).tntMass; + output.AppendLine($"- Blast radius: {Math.Round(BlastPhysicsUtils.CalculateBlastRange(tntMass), 2)} m"); + output.AppendLine($"- tnt Mass: {tntMass} kg"); + break; + } + partModules.Dispose(); + + return output.ToString(); + } + } +} diff --git a/BDArmory/Modules/MissileTurret.cs b/BDArmory/Modules/MissileTurret.cs new file mode 100644 index 000000000..435056026 --- /dev/null +++ b/BDArmory/Modules/MissileTurret.cs @@ -0,0 +1,644 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Guidances; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class MissileTurret : PartModule + { + [KSPField] public string finalTransformName; + public Transform finalTransform; + + [KSPField] public int turretID = 0; + + ModuleTurret turret; + + [KSPField(guiActive = true, guiName = "#LOC_BDArmory_TurretEnabled")] public bool turretEnabled;//Turret Enabled + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_AutoReturn"),//Auto-Return + UI_Toggle(scene = UI_Scene.Editor)] + public bool autoReturn = true; + + bool hasReturned = true; + + [KSPField] public float railLength = 3; + + Coroutine returnRoutine; + + int missileCount; + MissileLauncher[] missileChildren; + Transform[] missileTransforms; + Transform[] missileReferenceTransforms; + + Dictionary comOffsets; + + public bool slaved; + + public Vector3 slavedTargetPosition; + + bool pausingAfterShot; + float timeFired; + [KSPField] public float firePauseTime = 0.25f; + + ModuleRadar attachedRadar; + bool hasAttachedRadar; + [KSPField] public bool disableRadarYaw = false; + [KSPField] public bool disableRadarPitch = false; + + [KSPField] public bool mouseControllable = true; + + //animation + [KSPField] public string deployAnimationName; + AnimationState deployAnimState; + bool hasDeployAnimation; + [KSPField] public float deployAnimationSpeed = 1; + bool editorDeployed; + Coroutine deployAnimRoutine; + + //special + [KSPField] public bool activeMissileOnly = false; + + MissileFire wm; + + public MissileFire weaponManager + { + get + { + if (wm && wm.vessel == vessel) return wm; + wm = null; + + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + wm = mf.Current; + break; + } + mf.Dispose(); + return wm; + } + } + + IEnumerator DeployAnimation(bool forward) + { + yield return null; + + if (forward) + { + while (deployAnimState.normalizedTime < 1) + { + deployAnimState.speed = deployAnimationSpeed; + yield return null; + } + + deployAnimState.normalizedTime = 1; + } + else + { + deployAnimState.speed = 0; + + while (pausingAfterShot) + { + yield return new WaitForFixedUpdate(); + } + + while (deployAnimState.normalizedTime > 0) + { + deployAnimState.speed = -deployAnimationSpeed; + yield return null; + } + + deployAnimState.normalizedTime = 0; + } + + deployAnimState.speed = 0; + } + + public void EnableTurret() + { + if (!HighLogic.LoadedSceneIsFlight) + { + return; + } + + if (returnRoutine != null) + { + StopCoroutine(returnRoutine); + returnRoutine = null; + } + + turretEnabled = true; + hasReturned = false; + + if (hasAttachedRadar) + { + attachedRadar.lockingYaw = !disableRadarYaw; + attachedRadar.lockingPitch = !disableRadarPitch; + } + + if (!autoReturn) + { + Events["ReturnTurret"].guiActive = false; + } + + if (hasDeployAnimation) + { + if (deployAnimRoutine != null) + { + StopCoroutine(deployAnimRoutine); + } + + deployAnimRoutine = StartCoroutine(DeployAnimation(true)); + } + } + + public void DisableTurret() + { + turretEnabled = false; + + if (autoReturn) + { + hasReturned = true; + if (returnRoutine != null) + { + StopCoroutine(returnRoutine); + } + returnRoutine = StartCoroutine(ReturnRoutine()); + } + + if (hasAttachedRadar) + { + attachedRadar.lockingYaw = true; + attachedRadar.lockingPitch = true; + } + + if (!autoReturn) + { + Events["ReturnTurret"].guiActive = true; + } + + if (hasDeployAnimation) + { + if (deployAnimRoutine != null) + { + StopCoroutine(deployAnimRoutine); + } + + deployAnimRoutine = StartCoroutine(DeployAnimation(false)); + } + } + + [KSPEvent(guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_ReturnTurret")]//Return Turret + public void ReturnTurret() + { + if (!turretEnabled) + { + returnRoutine = StartCoroutine(ReturnRoutine()); + hasReturned = true; + } + } + + [KSPEvent(guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_ToggleAnimation")]//Toggle Animation + public void EditorToggleAnimation() + { + editorDeployed = !editorDeployed; + + if (deployAnimRoutine != null) + { + StopCoroutine(deployAnimRoutine); + } + + deployAnimRoutine = StartCoroutine(DeployAnimation(editorDeployed)); + } + + IEnumerator ReturnRoutine() + { + if (turretEnabled) + { + hasReturned = false; + yield break; + } + + yield return new WaitForSeconds(0.25f); + + while (pausingAfterShot) + { + yield return new WaitForFixedUpdate(); + } + + while (turret != null && !turret.ReturnTurret()) + { + UpdateMissilePositions(); + yield return new WaitForFixedUpdate(); + } + } + + public override void OnStart(StartState state) + { + base.OnStart(state); + + part.force_activate(); + + //setup anim + if (!string.IsNullOrEmpty(deployAnimationName)) + { + hasDeployAnimation = true; + deployAnimState = Misc.Misc.SetUpSingleAnimation(deployAnimationName, part); + if (state == StartState.Editor) + { + Events["EditorToggleAnimation"].guiActiveEditor = true; + } + } + + if (HighLogic.LoadedSceneIsFlight) + { + List.Enumerator tur = part.FindModulesImplementing().GetEnumerator(); + while (tur.MoveNext()) + { + if (tur.Current == null) continue; + if (tur.Current.turretID != turretID) continue; + turret = tur.Current; + break; + } + tur.Dispose(); + + attachedRadar = part.FindModuleImplementing(); + if (attachedRadar) hasAttachedRadar = true; + + finalTransform = part.FindModelTransform(finalTransformName); + + UpdateMissileChildren(); + + if (!autoReturn) + { + Events["ReturnTurret"].guiActive = true; + } + } + } + + public override void OnFixedUpdate() + { + base.OnFixedUpdate(); + + if (turretEnabled) + { + hasReturned = false; + + if (missileCount == 0) + { + DisableTurret(); + return; + } + + Aim(); + UpdateMissilePositions(); + + if (!vessel.IsControllable) + { + DisableTurret(); + } + } + else + { + if (Quaternion.FromToRotation(finalTransform.forward, turret.yawTransform.parent.parent.forward) != + Quaternion.identity) + { + UpdateMissilePositions(); + } + + if (autoReturn && !hasReturned) + { + DisableTurret(); + } + } + + pausingAfterShot = (Time.time - timeFired < firePauseTime); + } + + void Aim() + { + UpdateTarget(); + + if (slaved) + { + SlavedAim(); + } + else + { + if (weaponManager && wm.guardMode) + { + return; + } + + if (mouseControllable && vessel.isActiveVessel) + { + MouseAim(); + } + } + } + + void UpdateTarget() + { + slaved = false; + + if (weaponManager && wm.slavingTurrets && wm.CurrentMissile) + { + slaved = true; + slavedTargetPosition = MissileGuidance.GetAirToAirFireSolution(wm.CurrentMissile, wm.slavedPosition, + wm.slavedVelocity); + } + } + + public void SlavedAim() + { + if (pausingAfterShot) return; + + turret.AimToTarget(slavedTargetPosition); + } + + void MouseAim() + { + if (pausingAfterShot) return; + + Vector3 targetPosition; + float maxTargetingRange = 5000; + + //MouseControl + Vector3 mouseAim = new Vector3(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, 0); + Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mouseAim); + RaycastHit hit; + //KerbalEVA hitEVA = null; + //if (Physics.Raycast(ray, out hit, maxTargetingRange, 2228224)) + //{ + // targetPosition = hit.point; + // hitEVA = hit.collider.gameObject.GetComponentUpwards(); + + // if (hitEVA && hitEVA.part.vessel && hitEVA.part.vessel == vessel) + // { + // targetPosition = ray.direction * maxTargetingRange + FlightCamera.fetch.mainCamera.transform.position; + // } + //} + + if (Physics.Raycast(ray, out hit, maxTargetingRange, 9076737)) + { + targetPosition = hit.point; + + //aim through self vessel if occluding mouseray + KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards(); + Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent(); + if (p && p.vessel && p.vessel == vessel) + { + targetPosition = ray.direction * maxTargetingRange + FlightCamera.fetch.mainCamera.transform.position; + } + } + else + { + targetPosition = (ray.direction * (maxTargetingRange + (FlightCamera.fetch.Distance * 0.75f))) + + FlightCamera.fetch.mainCamera.transform.position; + } + + turret.AimToTarget(targetPosition); + } + + public void UpdateMissileChildren() + { + missileCount = 0; + + //setup com dictionary + if (comOffsets == null) + { + comOffsets = new Dictionary(); + } + + //destroy the existing reference transform objects + if (missileReferenceTransforms != null) + { + for (int i = 0; i < missileReferenceTransforms.Length; i++) + { + if (missileReferenceTransforms[i]) + { + Destroy(missileReferenceTransforms[i].gameObject); + } + } + } + + List msl = new List(); + List mtfl = new List(); + List mrl = new List(); + + List.Enumerator child = part.children.GetEnumerator(); + while (child.MoveNext()) + { + if (child.Current == null) continue; + if (child.Current.parent != part) continue; + + MissileLauncher ml = child.Current.FindModuleImplementing(); + + if (!ml) continue; + + Transform mTf = child.Current.FindModelTransform("missileTransform"); + //fix incorrect hierarchy + if (!mTf) + { + Transform modelTransform = ml.part.partTransform.Find("model"); + + mTf = new GameObject("missileTransform").transform; + Transform[] tfchildren = new Transform[modelTransform.childCount]; + for (int i = 0; i < modelTransform.childCount; i++) + { + tfchildren[i] = modelTransform.GetChild(i); + } + mTf.parent = modelTransform; + mTf.localPosition = Vector3.zero; + mTf.localRotation = Quaternion.identity; + mTf.localScale = Vector3.one; + IEnumerator t = tfchildren.AsEnumerable().GetEnumerator(); + while (t.MoveNext()) + { + if (t.Current == null) continue; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory] : MissileTurret moving transform: " + t.Current.gameObject.name); + t.Current.parent = mTf; + } + t.Dispose(); + } + + if (!ml || !mTf) continue; + msl.Add(ml); + mtfl.Add(mTf); + Transform mRef = new GameObject().transform; + mRef.position = mTf.position; + mRef.rotation = mTf.rotation; + mRef.parent = finalTransform; + mrl.Add(mRef); + + ml.MissileReferenceTransform = mTf; + ml.missileTurret = this; + + if (!comOffsets.ContainsKey(ml.part.name)) + { + comOffsets.Add(ml.part.name, ml.part.CoMOffset); + } + + missileCount++; + } + child.Dispose(); + + missileChildren = msl.ToArray(); + missileTransforms = mtfl.ToArray(); + missileReferenceTransforms = mrl.ToArray(); + } + + void UpdateMissilePositions() + { + if (missileCount == 0) + { + return; + } + + for (int i = 0; i < missileChildren.Length; i++) + { + if (missileTransforms[i] && missileChildren[i] && !missileChildren[i].HasFired) + { + missileTransforms[i].position = missileReferenceTransforms[i].position; + missileTransforms[i].rotation = missileReferenceTransforms[i].rotation; + + Part missilePart = missileChildren[i].part; + if (missilePart != null) + { + Vector3 newCoMOffset = + missilePart.transform.InverseTransformPoint( + missileTransforms[i].TransformPoint(comOffsets[missilePart.name])); + missilePart.CoMOffset = newCoMOffset; + } + } + } + } + + public void FireMissile(int index) + { + if (index < missileCount && missileChildren != null && missileChildren[index] != null) + { + PrepMissileForFire(index); + + if (weaponManager) + { + wm.SendTargetDataToMissile(missileChildren[index]); + } + missileChildren[index].FireMissile(); + StartCoroutine(MissileRailRoutine(missileChildren[index])); + if (wm) + { + wm.UpdateList(); + } + + UpdateMissileChildren(); + + timeFired = Time.time; + } + } + + public void FireMissile(MissileLauncher ml) + { + int index = IndexOfMissile(ml); + if (index >= 0) + { + Debug.Log("[BDArmory] : Firing missile index: " + index); + FireMissile(index); + } + else + { + Debug.Log("[BDArmory] : Tried to fire a missile that doesn't exist or is not attached to the turret."); + } + } + + IEnumerator MissileRailRoutine(MissileLauncher ml) + { + yield return null; + Ray ray = new Ray(ml.transform.position, ml.MissileReferenceTransform.forward); + Vector3 localOrigin = turret.pitchTransform.InverseTransformPoint(ray.origin); + Vector3 localDirection = turret.pitchTransform.InverseTransformDirection(ray.direction); + float forwardSpeed = ml.decoupleSpeed; + while (ml && Vector3.SqrMagnitude(ml.transform.position - ray.origin) < railLength * railLength) + { + float thrust = ml.TimeIndex < ml.boostTime ? ml.thrust : ml.cruiseThrust; + thrust = ml.TimeIndex < ml.boostTime + ml.cruiseTime ? thrust : 0; + float accel = thrust / ml.part.mass; + forwardSpeed += accel * Time.fixedDeltaTime; + + ray.origin = turret.pitchTransform.TransformPoint(localOrigin); + ray.direction = turret.pitchTransform.TransformDirection(localDirection); + + Vector3 projPos = Vector3.Project(ml.vessel.transform.position - ray.origin, ray.direction) + ray.origin; + Vector3 railVel = part.rb.GetPointVelocity(projPos); + //Vector3 projVel = Vector3.Project(ml.vessel.Velocity-railVel, ray.direction); + + ml.vessel.SetPosition(projPos); + ml.vessel.SetWorldVelocity(railVel + (forwardSpeed * ray.direction)); + + yield return new WaitForFixedUpdate(); + + ray.origin = turret.pitchTransform.TransformPoint(localOrigin); + ray.direction = turret.pitchTransform.TransformDirection(localDirection); + } + } + + void PrepMissileForFire(int index) + { + Debug.Log("[BDArmory] : Prepping missile for turret fire."); + missileTransforms[index].localPosition = Vector3.zero; + missileTransforms[index].localRotation = Quaternion.identity; + missileChildren[index].part.partTransform.position = missileReferenceTransforms[index].position; + missileChildren[index].part.partTransform.rotation = missileReferenceTransforms[index].rotation; + + missileChildren[index].part.CoMOffset = comOffsets[missileChildren[index].part.name]; + } + + public void PrepMissileForFire(MissileLauncher ml) + { + int index = IndexOfMissile(ml); + + if (index >= 0) + { + PrepMissileForFire(index); + } + else + { + Debug.Log("[BDArmory] : Tried to prep a missile for firing that doesn't exist or is not attached to the turret."); + } + } + + private int IndexOfMissile(MissileLauncher ml) + { + if (missileCount == 0) return -1; + + for (int i = 0; i < missileCount; i++) + { + if (missileChildren[i] && missileChildren[i] == ml) + { + return i; + } + } + + return -1; + } + + public bool ContainsMissileOfType(MissileLauncher ml) + { + if (!ml) return false; + if (missileCount == 0) return false; + + for (int i = 0; i < missileCount; i++) + { + if ((missileChildren[i]) && missileChildren[i].part.name == ml.part.name) + { + return true; + } + } + return false; + } + } +} diff --git a/BDArmory/Modules/ModuleAmmoSwitch.cs b/BDArmory/Modules/ModuleAmmoSwitch.cs new file mode 100644 index 000000000..06f0bbb6e --- /dev/null +++ b/BDArmory/Modules/ModuleAmmoSwitch.cs @@ -0,0 +1,401 @@ +using System.Collections.Generic; +using System.Text; +using BDArmory.Misc; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class ModuleAmmoSwitch : PartModule, IPartCostModifier + { + [KSPField] + public string resourceNames = "ElectricCharge;LiquidFuel,Oxidizer;MonoPropellant"; + + [KSPField] + public string resourceAmounts = "100;75,25;200"; + + [KSPField] + public string initialResourceAmounts = ""; + + [KSPField] + public float basePartMass = 0.25f; + + [KSPField] + public string tankMass = "0;0;0;0"; + + [KSPField] + public string tankCost = "0; 0; 0; 0"; + + [KSPField] + public bool displayCurrentTankCost = false; + + [KSPField] + public bool hasGUI = true; + + [KSPField] + public bool availableInFlight = false; + + [KSPField] + public bool availableInEditor = true; + + [KSPField(isPersistant = true)] + public int selectedTankSetup = -1; + + [KSPField(isPersistant = true)] + public bool hasLaunched = false; + + [KSPField] + public bool showInfo = true; // if false, does not feed info to the part list pop up info menu + + [KSPField(guiActive = false, guiActiveEditor = false, guiName = "#LOC_BDArmory_AddedCost")]//Added cost + public float addedCost = 0f; + + [KSPField(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_DryMass")]//Dry mass + public float dryMassInfo = 0f; + private List tankList; + private List weightList; + private List tankCostList; + private bool initialized = false; + + [KSPField(isPersistant = true)] + public bool configLoaded = false; + + UIPartActionWindow tweakableUI; + + public override void OnStart(PartModule.StartState state) + { + initializeData(); + if (selectedTankSetup == -1) + { + selectedTankSetup = 0; + assignResourcesToPart(false); + } + } + + public override void OnAwake() + { + //Debug.Log("FS AWAKE "+initialized+" "+configLoaded+" "+resourceAmounts); + if (configLoaded) + { + initializeData(); + } + //Debug.Log("FS AWAKE DONE " + (configLoaded ? tankList.Count.ToString() : "NO CONFIG")); + } + + public override void OnLoad(ConfigNode node) + { + base.OnLoad(node); + //Debug.Log("FS LOAD " + initialized + " " + resourceAmounts+configLoaded); + if (!configLoaded) + { + initializeData(); + } + if (basePartMass != part.mass) + { + Debug.LogError("Error: BDAcAmmoSwitch Mass Discrepancy detected in part '" + part.name + "'.", part); + } + configLoaded = true; + //Debug.Log("FS LOAD DONE " + tankList.Count); + } + + private void initializeData() + { + if (!initialized) + { + setupTankList(false); + weightList = BDAcTools.ParseDoubles(tankMass); + tankCostList = BDAcTools.ParseDoubles(tankCost); + if (HighLogic.LoadedSceneIsFlight) hasLaunched = true; + if (hasGUI) + { + Events["nextTankSetupEvent"].guiActive = availableInFlight; + Events["nextTankSetupEvent"].guiActiveEditor = availableInEditor; + Events["previousTankSetupEvent"].guiActive = availableInFlight; + Events["previousTankSetupEvent"].guiActiveEditor = availableInEditor; + } + else + { + Events["nextTankSetupEvent"].guiActive = false; + Events["nextTankSetupEvent"].guiActiveEditor = false; + Events["previousTankSetupEvent"].guiActive = false; + Events["previousTankSetupEvent"].guiActiveEditor = false; + } + + if (HighLogic.CurrentGame == null || HighLogic.CurrentGame.Mode == Game.Modes.CAREER) + { + Fields["addedCost"].guiActiveEditor = displayCurrentTankCost; + } + + initialized = true; + } + } + + [KSPEvent(guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_NextTankSetup")]//Next tank setup + public void nextTankSetupEvent() + { + selectedTankSetup++; + if (selectedTankSetup >= tankList.Count) + { + selectedTankSetup = 0; + } + assignResourcesToPart(true); + } + + [KSPEvent(guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_PreviousTankSetup")]//Previous tank setup + public void previousTankSetupEvent() + { + selectedTankSetup--; + if (selectedTankSetup < 0) + { + selectedTankSetup = tankList.Count - 1; + } + assignResourcesToPart(true); + } + + public void selectTankSetup(int i, bool calledByPlayer) + { + initializeData(); + if (selectedTankSetup != i) + { + selectedTankSetup = i; + assignResourcesToPart(calledByPlayer); + } + } + + private void assignResourcesToPart(bool calledByPlayer) + { + // destroying a resource messes up the gui in editor, but not in flight. + setupTankInPart(part, calledByPlayer); + if (HighLogic.LoadedSceneIsEditor) + { + for (int s = 0; s < part.symmetryCounterparts.Count; s++) + { + setupTankInPart(part.symmetryCounterparts[s], calledByPlayer); + ModuleAmmoSwitch symSwitch = part.symmetryCounterparts[s].GetComponent(); + if (symSwitch != null) + { + symSwitch.selectedTankSetup = selectedTankSetup; + } + } + } + + //Debug.Log("refreshing UI"); + + if (tweakableUI == null) + { + tweakableUI = BDAcTools.FindActionWindow(part); + } + if (tweakableUI != null) + { + tweakableUI.displayDirty = true; + } + else + { + Debug.Log("no UI to refresh"); + } + } + + private void setupTankInPart(Part currentPart, bool calledByPlayer) + { + currentPart.Resources.dict = new DictionaryValueList(); + PartResource[] partResources = currentPart.GetComponents(); + //for (int i = 0; i < partResources.Length; i++) + //{ + // DestroyImmediate(partResources[i]); + //} + + for (int tankCount = 0; tankCount < tankList.Count; tankCount++) + { + if (selectedTankSetup == tankCount) + { + for (int resourceCount = 0; resourceCount < tankList[tankCount].resources.Count; resourceCount++) + { + if (tankList[tankCount].resources[resourceCount].name != "Structural") + { + //Debug.Log("new node: " + tankList[i].resources[j].name); + ConfigNode newResourceNode = new ConfigNode("RESOURCE"); + newResourceNode.AddValue("name", tankList[tankCount].resources[resourceCount].name); + newResourceNode.AddValue("maxAmount", tankList[tankCount].resources[resourceCount].maxAmount); + if (calledByPlayer && !HighLogic.LoadedSceneIsEditor) + { + newResourceNode.AddValue("amount", 0.0f); + } + else + { + newResourceNode.AddValue("amount", tankList[tankCount].resources[resourceCount].amount); + } + + //Debug.Log("add node to part"); + currentPart.AddResource(newResourceNode); + } + else + { + //Debug.Log("Skipping structural fuel type"); + } + } + } + } + + updateWeight(currentPart, selectedTankSetup); + updateCost(); + } + + private float updateCost() + { + if (selectedTankSetup >= 0 && selectedTankSetup < tankCostList.Count) + { + addedCost = (float)tankCostList[selectedTankSetup]; + } + else + { + addedCost = 0f; + } + //GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship); //crashes game + return addedCost; + } + + private void updateWeight(Part currentPart, int newTankSetup) + { + if (newTankSetup < weightList.Count) + { + currentPart.mass = (float)(basePartMass + weightList[newTankSetup]); + } + } + + public override void OnUpdate() + { + } + + public void Update() + { + if (HighLogic.LoadedSceneIsEditor) + { + dryMassInfo = part.mass; + } + } + + private void setupTankList(bool calledByPlayer) + { + tankList = new List(); + weightList = new List(); + tankCostList = new List(); + + // First find the amounts each tank type is filled with + + List> resourceList = new List>(); + List> initialResourceList = new List>(); + string[] resourceTankArray = resourceAmounts.Split(';'); + string[] initialResourceTankArray = initialResourceAmounts.Split(';'); + if (initialResourceAmounts.Equals("") || + initialResourceTankArray.Length != resourceTankArray.Length) + { + initialResourceTankArray = resourceTankArray; + } + //Debug.Log("FSDEBUGRES: " + resourceTankArray.Length+" "+resourceAmounts); + for (int tankCount = 0; tankCount < resourceTankArray.Length; tankCount++) + { + resourceList.Add(new List()); + initialResourceList.Add(new List()); + string[] resourceAmountArray = resourceTankArray[tankCount].Trim().Split(','); + string[] initialResourceAmountArray = initialResourceTankArray[tankCount].Trim().Split(','); + if (initialResourceAmounts.Equals("") || + initialResourceAmountArray.Length != resourceAmountArray.Length) + { + initialResourceAmountArray = resourceAmountArray; + } + for (int amountCount = 0; amountCount < resourceAmountArray.Length; amountCount++) + { + try + { + resourceList[tankCount].Add(double.Parse(resourceAmountArray[amountCount].Trim())); + initialResourceList[tankCount].Add(double.Parse(initialResourceAmountArray[amountCount].Trim())); + } + catch + { + Debug.Log("BDAcAmmoSwitch: error parsing resource amount " + tankCount + "/" + amountCount + ": '" + resourceTankArray[amountCount] + "': '" + resourceAmountArray[amountCount].Trim() + "'"); + } + } + } + + // Then find the kinds of resources each tank holds, and fill them with the amounts found previously, or the amount hey held last (values kept in save persistence/craft) + + string[] tankArray = resourceNames.Split(';'); + for (int tankCount = 0; tankCount < tankArray.Length; tankCount++) + { + BDAcUniversalAmmo newTank = new BDAcUniversalAmmo(); + tankList.Add(newTank); + string[] resourceNameArray = tankArray[tankCount].Split(','); + for (int nameCount = 0; nameCount < resourceNameArray.Length; nameCount++) + { + BDAcAmmo newResource = new BDAcAmmo(resourceNameArray[nameCount].Trim(' ')); + if (resourceList[tankCount] != null) + { + if (nameCount < resourceList[tankCount].Count) + { + newResource.maxAmount = resourceList[tankCount][nameCount]; + newResource.amount = initialResourceList[tankCount][nameCount]; + } + } + newTank.resources.Add(newResource); + } + } + } + + public override string GetInfo() + { + if (showInfo) + { + List resourceList = BDAcTools.ParseNames(resourceNames); + StringBuilder info = new StringBuilder(); + info.AppendLine("Ammo Box setups available:"); + for (int i = 0; i < resourceList.Count; i++) + { + info.AppendLine(resourceList[i].Replace(",", ", ")); + } + return info.ToString(); + } + else + return string.Empty; + } + + public float GetModuleCost(float defaultCost, ModifierStagingSituation sit) + { + return updateCost(); + } + + public ModifierChangeWhen GetModuleCostChangeWhen() + { + return ModifierChangeWhen.CONSTANTLY; + } + } + + // Supporting classes + public class BDAcUniversalAmmo + { + public List resources = new List(); + } + + public class BDAcAmmo + { + //public PartResource resource; + public string name; + public int ID; + public float ratio; + public double currentSupply = 0f; + public double amount = 0f; + public double maxAmount = 0f; + + public BDAcAmmo(string _name, float _ratio) + { + name = _name; + ID = _name.GetHashCode(); + ratio = _ratio; + } + + public BDAcAmmo(string _name) + { + name = _name; + ID = _name.GetHashCode(); + ratio = 1f; + } + } +} diff --git a/BDArmory/Modules/ModuleDrainEC.cs b/BDArmory/Modules/ModuleDrainEC.cs new file mode 100644 index 000000000..6d6cfe028 --- /dev/null +++ b/BDArmory/Modules/ModuleDrainEC.cs @@ -0,0 +1,176 @@ +using System.Linq; + +namespace BDArmory.Modules +{ + public class ModuleDrainEC : PartModule + { + public bool armed = true; + private bool setup = true; + private int minCrew = 0; + + public override void OnStart(StartState state) + { + if (HighLogic.LoadedSceneIsFlight) + { + part.force_activate(); + vessel.OnFlyByWire += ThrottleControl; + part.OnJustAboutToBeDestroyed += EnableVessel; + } + base.OnStart(state); + } + + public void Update() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (armed) + { + DisableVessel(); + } + else + { + EnableVessel(); + } + } + } + + void ThrottleControl(FlightCtrlState s) + { + this.vessel.Autopilot.Enabled = false; + s.mainThrottle = 0; + s.rollTrim += 0.1f; + s.wheelSteerTrim += 0.1f; + s.yawTrim += 0.1f; + s.yaw += 0.1f; + s.roll += 0.1f; + s.pitch -= 0.1f; + s.pitchTrim -= 0.1f; + } + + private void EnableVessel() + { + foreach (Part p in vessel.parts) + { + var command = p.FindModuleImplementing(); + + if (command != null) + { + //command.minimumCrew = minCrew; + } + + foreach (ModuleEnginesFX engineFX in p.Modules) + { + engineFX.allowRestart = true; + } + + foreach (ModuleEngines engine in p.Modules) + { + engine.allowRestart = true; + } + } + + Destroy(this); + } + + private void DisableVessel() + { + vessel.OnFlyByWire -= ThrottleControl; + vessel.OnFlyByWire += ThrottleControl; + + if (setup) + { + setup = false; + + foreach (Part p in this.vessel.parts) + { + var camera = p.FindModuleImplementing(); + var radar = p.FindModuleImplementing(); + var spaceRadar = p.FindModuleImplementing(); + + if (radar != null) + { + if (radar.radarEnabled) + { + radar.DisableRadar(); + } + } + + if (spaceRadar != null) + { + if (spaceRadar.radarEnabled) + { + spaceRadar.DisableRadar(); + } + } + + if (camera != null) + { + if (camera.cameraEnabled) + { + camera.DisableCamera(); + } + } + + var command = p.FindModuleImplementing(); + var weapon = p.FindModuleImplementing(); + var turret = p.FindModuleImplementing(); + + if (turret != null) + { + turret.maxPitch = 0; + turret.yawRange = 0; + turret.yawRangeLimit = 0; + } + + if (weapon != null) + { + weapon.onlyFireInRange = true; + weapon.engageRangeMax = 0; + weapon.engageRangeMin = 0; + weapon.engageSLW = false; + weapon.engageMissile = false; + weapon.engageGround = false; + weapon.engageAir = false; + } + + if (command != null) + { + minCrew = command.minimumCrew; + //command.minimumCrew = 100; + } + + var PAI = this.vessel.FindPartModuleImplementing(); + var SAI = this.vessel.FindPartModuleImplementing(); + + if (SAI != null) + { + if (SAI.pilotEnabled) + { + SAI.TogglePilot(); + } + } + + if (PAI != null) + { + if (PAI.pilotEnabled) + { + PAI.TogglePilot(); + } + } + } + } + + foreach (Part p in vessel.parts) + { + PartResource r = p.Resources.Where(pr => pr.resourceName == "ElectricCharge").FirstOrDefault(); + if (r != null) + { + if (r.amount >= 0) + { + p.RequestResource("ElectricCharge", r.amount); + } + } + } + } + } +} diff --git a/BDArmory/Modules/ModuleECMJammer.cs b/BDArmory/Modules/ModuleECMJammer.cs new file mode 100644 index 000000000..393d3062a --- /dev/null +++ b/BDArmory/Modules/ModuleECMJammer.cs @@ -0,0 +1,183 @@ +using System.Text; +using BDArmory.CounterMeasure; + +namespace BDArmory.Modules +{ + public class ModuleECMJammer : PartModule + { + [KSPField] public float jammerStrength = 700; + + [KSPField] public float lockBreakerStrength = 500; + + [KSPField] public float rcsReductionFactor = 0.75f; + + [KSPField] public double resourceDrain = 5; + + [KSPField] public bool alwaysOn = false; + + [KSPField] public bool signalSpam = true; + + [KSPField] public bool lockBreaker = true; + + [KSPField] public bool rcsReduction = false; + + [KSPField(isPersistant = true, guiActive = true, guiName = "#LOC_BDArmory_Enabled")]//Enabled + public bool jammerEnabled = false; + + VesselECMJInfo vesselJammer; + + [KSPAction("Enable")] + public void AGEnable(KSPActionParam param) + { + if (!jammerEnabled) + { + EnableJammer(); + } + } + + [KSPAction("Disable")] + public void AGDisable(KSPActionParam param) + { + if (jammerEnabled) + { + DisableJammer(); + } + } + + [KSPAction("Toggle")] + public void AGToggle(KSPActionParam param) + { + Toggle(); + } + + [KSPEvent(guiActiveEditor = false, guiActive = true, guiName = "#LOC_BDArmory_Toggle")]//Toggle + public void Toggle() + { + if (jammerEnabled) + { + DisableJammer(); + } + else + { + EnableJammer(); + } + } + + public override void OnStart(StartState state) + { + base.OnStart(state); + if (!HighLogic.LoadedSceneIsFlight) return; + part.force_activate(); + + GameEvents.onVesselCreate.Add(OnVesselCreate); + } + + void OnDestroy() + { + GameEvents.onVesselCreate.Remove(OnVesselCreate); + } + + void OnVesselCreate(Vessel v) + { + EnsureVesselJammer(); + } + + public void EnableJammer() + { + EnsureVesselJammer(); + vesselJammer.AddJammer(this); + jammerEnabled = true; + } + + public void DisableJammer() + { + EnsureVesselJammer(); + + vesselJammer.RemoveJammer(this); + jammerEnabled = false; + } + + public override void OnFixedUpdate() + { + base.OnFixedUpdate(); + + if (alwaysOn && !jammerEnabled) + { + EnableJammer(); + } + + if (jammerEnabled) + { + EnsureVesselJammer(); + + DrainElectricity(); + } + } + + void EnsureVesselJammer() + { + /* + if (vesselJammer == null) + { + return; + } + if (vesselJammer.vessel == null) + { + return; + } + if (vessel == null) + { + return; + } + */ + + if (!vesselJammer || vesselJammer.vessel != vessel) + { + vesselJammer = vessel.gameObject.GetComponent(); + if (!vesselJammer) + { + vesselJammer = vessel.gameObject.AddComponent(); + } + } + + vesselJammer.DelayedCleanJammerList(); + } + + void DrainElectricity() + { + if (resourceDrain <= 0) + { + return; + } + + double drainAmount = resourceDrain * TimeWarp.fixedDeltaTime; + double chargeAvailable = part.RequestResource("ElectricCharge", drainAmount, ResourceFlowMode.ALL_VESSEL); + if (chargeAvailable < drainAmount * 0.95f) + { + DisableJammer(); + } + } + + // RMB info in editor + public override string GetInfo() + { + StringBuilder output = new StringBuilder(); + output.AppendLine($"EC/sec: {resourceDrain}"); + output.AppendLine($"Always on: {alwaysOn}"); + output.AppendLine($"RCS reduction: {rcsReduction}"); + if (rcsReduction) + { + output.AppendLine($" - factor: {rcsReductionFactor}"); + } + output.AppendLine($"Lockbreaker: {lockBreaker}"); + if (lockBreaker) + { + output.AppendLine($" - strength: {lockBreakerStrength}"); + } + output.AppendLine($"Signal strength: {jammerStrength}"); + output.AppendLine($"(increases detectability!)"); + + return output.ToString(); + } + } +} diff --git a/BDArmory/Modules/ModuleEMP.cs b/BDArmory/Modules/ModuleEMP.cs new file mode 100644 index 000000000..217deffbc --- /dev/null +++ b/BDArmory/Modules/ModuleEMP.cs @@ -0,0 +1,51 @@ +namespace BDArmory.Modules +{ + public class ModuleEMP : PartModule + { + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_EMPBlastRadius"),//EMP Blast Radius + UI_Label(affectSymCounterparts = UI_Scene.All, controlEnabled = true, scene = UI_Scene.All)] + public float proximity = 5000; + + public override void OnStart(StartState state) + { + if (HighLogic.LoadedSceneIsFlight) + { + part.force_activate(); + part.OnJustAboutToBeDestroyed += DetonateEMPRoutine; + } + base.OnStart(state); + } + + public void DetonateEMPRoutine() + { + foreach (Vessel v in FlightGlobals.Vessels) + { + if (!v.HoldPhysics) + { + double targetDistance = Vector3d.Distance(this.vessel.GetWorldPos3D(), v.GetWorldPos3D()); + + if (targetDistance <= proximity) + { + var count = 0; + + foreach (Part p in v.parts) + { + var wmPart = p.FindModuleImplementing(); + + if (wmPart != null) + { + count = 1; + p.AddModule("ModuleDrainEC"); + } + } + + if (count == 0) + { + v.rootPart.AddModule("ModuleDrainEC"); + } + } + } + } + } + } +} diff --git a/BDArmory/Modules/ModuleMissileRearm.cs b/BDArmory/Modules/ModuleMissileRearm.cs new file mode 100644 index 000000000..b74446b87 --- /dev/null +++ b/BDArmory/Modules/ModuleMissileRearm.cs @@ -0,0 +1,549 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using KSP.UI.Screens; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class ModuleMissileRearm : PartModule + { + private Transform MissileTransform = null; + + [KSPField(guiName = "#LOC_BDArmory_OrdinanceAvailable", guiActive = true, isPersistant = true)]//Ordinance Available + public int ammoCount = 20; + + [KSPField(guiName = "#LOC_BDArmory_MissileAssign", guiActive = true, isPersistant = true)]//Missile Assign + private string MissileName = "bahaAim120"; + + [KSPAction("Resupply", KSPActionGroup.None)] + private void ActionResupply(KSPActionParam param) + { + Resupply(); + } + + [KSPEvent(name = "Resupply", guiName = "#LOC_BDArmory_Resupply", active = true, guiActive = true)]//Resupply + public void Resupply() + { + if (this.part.children.Count != 0) + { + Debug.Log("Not Empty" + this.part.children.Count); + return; + } + if (ammoCount >= 1) + { + List availablePart = PartLoader.LoadedPartsList; + foreach (AvailablePart AP in availablePart) + { + if (AP.partPrefab.name == MissileName) + { + foreach (PartModule m in AP.partPrefab.Modules) + { + if (m.moduleName == "MissileLauncher") + { + var partNode = new ConfigNode(); + PartSnapshot(AP.partPrefab).CopyTo(partNode); + Debug.Log("Node" + AP.partPrefab.srfAttachNode.originalPosition); + CreatePart(partNode, MissileTransform.transform.position - MissileTransform.TransformDirection(AP.partPrefab.srfAttachNode.originalPosition), + this.part.transform.rotation, this.part, this.part, "srfAttach"); + ammoCount -= 1; + StartCoroutine(ResetTurret()); + return; + } + } + } + } + } + } + + IEnumerator ResetTurret() + { + yield return new WaitForEndOfFrame(); + yield return new WaitForEndOfFrame(); + + var turret = part.FindModuleImplementing(); + if (turret != null) + { + turret.UpdateMissileChildren(); + } + } + + //[KSPEvent(name = "Reassign", guiName = "Reassign", active = true, guiActive = true)] + public void Reassign() + { + if (this.part.children.Count == 1) + { + foreach (Part p in this.part.children) + { + foreach (PartModule m in p.Modules) + { + if (m.moduleName == "MissileLauncher") + { + MissileName = p.name; + Debug.Log(MissileName); + } + } + } + } + } + + public override void OnStart(PartModule.StartState state) + { + this.enabled = true; + this.part.force_activate(); + MissileTransform = base.part.FindModelTransform("MissileTransform"); + Reassign(); + } + + public override void OnFixedUpdate() + { + } + + [KSPEvent(name = "Resupply", guiName = "#LOC_BDArmory_Resupply", active = true, guiActive = false)]//Resupply + public static AttachNode GetAttachNodeById(Part p, string id) + { + var node = id == "srfAttach" ? p.srfAttachNode : p.FindAttachNode(id); + if (node == null) + { + Debug.Log("Cannot find attach node {0} on part {1}. Using srfAttach" + id + p); + node = p.srfAttachNode; + } + return node; + } + + public static ModuleDockingNode GetDockingNode( + Part part, string attachNodeId = null, AttachNode attachNode = null) + { + var nodeId = attachNodeId ?? (attachNode != null ? attachNode.id : null); + return part.FindModulesImplementing() + .FirstOrDefault(x => x.referenceAttachNode == nodeId); + } + + public static bool CoupleDockingPortWithPart(ModuleDockingNode dockingNode) + { + var tgtPart = dockingNode.referenceNode.attachedPart; + if (tgtPart == null) + { + Debug.Log( + "Node's part {0} is not attached to anything thru the reference node" + dockingNode.part); + return false; + } + if (dockingNode.state != dockingNode.st_ready.name) + { + Debug.Log("Hard reset docking node {0} from state '{1}' to '{2}'" + + dockingNode.part + dockingNode.state + dockingNode.st_ready.name); + dockingNode.dockedPartUId = 0; + dockingNode.dockingNodeModuleIndex = 0; + // Target part lived in real world for some time, so its state may be anything. + // Do a hard reset. + dockingNode.fsm.StartFSM(dockingNode.st_ready.name); + } + var initState = dockingNode.lateFSMStart(PartModule.StartState.None); + // Make sure part init catched the new state. + while (initState.MoveNext()) + { + // Do nothing. Just wait. + } + if (dockingNode.fsm.currentStateName != dockingNode.st_preattached.name) + { + Debug.Log("Node on {0} is unexpected state '{1}'" + + dockingNode.part + dockingNode.fsm.currentStateName); + return false; + } + Debug.Log("Successfully set docking node {0} to state {1} with part {2}" + + dockingNode.part + dockingNode.fsm.currentStateName + tgtPart); + return true; + } + + static IEnumerator WaitAndMakeLonePart(Part newPart, OnPartReady onPartReady) + { + Debug.Log("Create lone part vessel for {0}" + newPart); + string originatingVesselName = newPart.vessel.vesselName; + newPart.physicalSignificance = Part.PhysicalSignificance.NONE; + newPart.PromoteToPhysicalPart(); + newPart.Unpack(); + newPart.disconnect(true); + Vessel newVessel = newPart.gameObject.AddComponent(); + newVessel.id = Guid.NewGuid(); + if (newVessel.Initialize(false)) + { + newVessel.vesselName = Vessel.AutoRename(newVessel, originatingVesselName); + newVessel.IgnoreGForces(10); + newVessel.currentStage = StageManager.RecalculateVesselStaging(newVessel); + newPart.setParent(null); + } + yield return new WaitWhile(() => !newPart.started && newPart.State != PartStates.DEAD); + Debug.Log("Part {0} is in state {1}" + newPart + newPart.State); + if (newPart.State == PartStates.DEAD) + { + Debug.Log("Part {0} has died before fully instantiating" + newPart); + yield break; + } + + if (onPartReady != null) + { + onPartReady(newPart); + } + } + + public static void AwakePartModule(PartModule module) + { + // Private method can only be accessed via reflection when requested on the class that declares + // it. So, don't use type of the argument and specify it explicitly. + var moduleAwakeMethod = typeof(PartModule).GetMethod( + "Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (moduleAwakeMethod != null) + { + moduleAwakeMethod.Invoke(module, new object[] { }); + } + else + { + Debug.Log("Cannot find Awake() method on {0}. Skip awakening", module); + } + } + + public static void ResetPartModule(PartModule module) + { + // Private method can only be accessed via reflection when requested on the class that declares + // it. So, don't use type of the argument and specify it explicitly. + var moduleResetMethod = typeof(PartModule).GetMethod( + "UpdateMissileChildren", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (moduleResetMethod != null) + { + moduleResetMethod.Invoke(module, new object[] { }); + } + else + { + Debug.Log("Cannot find Awake() method on {0}. Skip awakening", module); + } + } + + public static void CleanupFieldsInModule(PartModule module) + { + // HACK: Fix uninitialized fields in science lab module. + var scienceModule = module as ModuleScienceLab; + if (scienceModule != null) + { + scienceModule.ExperimentData = new List(); + Debug.Log( + "WORKAROUND. Fix null field in ModuleScienceLab module on the part prefab: {0}", module); + } + + // Ensure the module is awaken. Otherwise, any access to base fields list will result in NRE. + // HACK: Accessing Fields property of a non-awaken module triggers NRE. If it happens then do + // explicit awakening of the *base* module class. + try + { + module.Fields.GetEnumerator(); + } + catch + { + Debug.Log( + "WORKAROUND. Module {0} on part prefab is not awaken. Call Awake on it", module); + AwakePartModule(module); + } + foreach (var field in module.Fields) + { + var baseField = field as BaseField; + if (baseField.isPersistant && baseField.GetValue(module) == null) + { + //var proto = new StandardOrdinaryTypesProto(); + //var defValue = proto.ParseFromString("", baseField.FieldInfo.FieldType); + //Debug.Log("WORKAROUND. Found null field {0} in module prefab {1}," + // + " fixing to default value of type {2}: {3}", + // baseField.name, module, baseField.FieldInfo.FieldType, defValue); + //baseField.SetValue(defValue, module); + } + } + } + + public static void CleanupModuleFieldsInPart(Part part) + { + var badModules = new List(); + foreach (var moduleObj in part.Modules) + { + var module = moduleObj as PartModule; + try + { + CleanupFieldsInModule(module); + } + catch + { + badModules.Add(module); + } + } + // Cleanup modules that block KIS. It's a bad thing to do but not working KIS is worse. + foreach (var moduleToDrop in badModules) + { + Debug.Log( + "Module on part prefab {0} is setup improperly: name={1}. Drop it!" + part, moduleToDrop); + part.RemoveModule(moduleToDrop); + } + } + + public static ConfigNode PartSnapshot(Part part) + { + if (ReferenceEquals(part, part.partInfo.partPrefab)) + { + // HACK: Prefab may have fields initialized to "null". Such fields cannot be saved via + // BaseFieldList when making a snapshot. So, go thru the persistent fields of all prefab + // modules and replace nulls with a default value of the type. It's unlikely we break + // something since by design such fields are not assumed to be used until loaded, and it's + // impossible to have "null" value read from a config. + CleanupModuleFieldsInPart(part); + } + + var node = new ConfigNode("PART"); + var snapshot = new ProtoPartSnapshot(part, null); + + snapshot.attachNodes = new List(); + snapshot.srfAttachNode = new AttachNodeSnapshot("attach,-1"); + snapshot.symLinks = new List(); + snapshot.symLinkIdxs = new List(); + snapshot.Save(node); + + // Prune unimportant data + node.RemoveValues("parent"); + node.RemoveValues("position"); + node.RemoveValues("rotation"); + node.RemoveValues("istg"); + node.RemoveValues("dstg"); + node.RemoveValues("sqor"); + node.RemoveValues("sidx"); + node.RemoveValues("attm"); + node.RemoveValues("srfN"); + node.RemoveValues("attN"); + node.RemoveValues("connected"); + node.RemoveValues("attached"); + node.RemoveValues("flag"); + + node.RemoveNodes("ACTIONS"); + + // Remove modules that are not in prefab since they won't load anyway + var module_nodes = node.GetNodes("MODULE"); + var prefab_modules = part.partInfo.partPrefab.GetComponents(); + node.RemoveNodes("MODULE"); + + for (int i = 0; i < prefab_modules.Length && i < module_nodes.Length; i++) + { + var module = module_nodes[i]; + var name = module.GetValue("name") ?? ""; + + node.AddNode(module); + + if (name == "KASModuleContainer") + { + // Containers get to keep their contents + module.RemoveNodes("EVENTS"); + } + else if (name.StartsWith("KASModule")) + { + // Prune the state of the KAS modules completely + module.ClearData(); + module.AddValue("name", name); + continue; + } + + module.RemoveNodes("ACTIONS"); + } + + return node; + } + + public delegate void OnPartReady(Part affectedPart); + + public static Part CreatePart(AvailablePart avPart, Vector3 position, Quaternion rotation, + Part fromPart) + { + var partNode = new ConfigNode(); + PartSnapshot(avPart.partPrefab).CopyTo(partNode); + return CreatePart(partNode, position, rotation, fromPart); + } + + /// Creates a new part from the config. + /// Config to read part from. + /// Initial position of the new part. + /// Initial rotation of the new part. + /// + /// Optional. Part to couple new part to. + /// + /// Optional. Attach node ID on the new part to use for coupling. It's required if coupling to + /// part is requested. + /// + /// + /// Optional. Attach node on the target part to use for coupling. It's required if + /// specifies a stack node. + /// + /// + /// Callback to call when new part is fully operational and its joint is created (if any). It's + /// undetermined how long it may take before the callback is called. The calling code must expect + /// that there will be several frame updates and at least one fixed frame update. + /// + /// + /// Tells if new part must be created without rigidbody and joint. It's only used to create + /// equippable parts. Any other use-case is highly unlikely. + /// + /// + public static Part CreatePart( + ConfigNode partConfig, + Vector3 position, + Quaternion rotation, + Part fromPart, + Part coupleToPart = null, + string srcAttachNodeId = null, + AttachNode tgtAttachNode = null, + OnPartReady onPartReady = null, + bool createPhysicsless = false) + { + // Sanity checks for the parameters. + if (coupleToPart != null) + { + if (srcAttachNodeId == null + || srcAttachNodeId == "srfAttach" && tgtAttachNode != null + || srcAttachNodeId != "srfAttach" + && (tgtAttachNode == null || tgtAttachNode.id == "srfAttach")) + { + // Best we can do is falling back to surface attach. + srcAttachNodeId = "srfAttach"; + tgtAttachNode = null; + } + } + + var refVessel = coupleToPart != null ? coupleToPart.vessel : fromPart.vessel; + var partNodeCopy = new ConfigNode(); + partConfig.CopyTo(partNodeCopy); + var snapshot = + new ProtoPartSnapshot(partNodeCopy, refVessel.protoVessel, HighLogic.CurrentGame); + if (HighLogic.CurrentGame.flightState.ContainsFlightID(snapshot.flightID) + || snapshot.flightID == 0) + { + snapshot.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); + } + snapshot.parentIdx = coupleToPart != null ? refVessel.parts.IndexOf(coupleToPart) : 0; + snapshot.position = position; + snapshot.rotation = rotation; + snapshot.stageIndex = 0; + snapshot.defaultInverseStage = 0; + snapshot.seqOverride = -1; + snapshot.inStageIndex = -1; + snapshot.attachMode = srcAttachNodeId == "srfAttach" + ? (int)AttachModes.SRF_ATTACH + : (int)AttachModes.STACK; + snapshot.attached = true; + snapshot.flagURL = fromPart.flagURL; + + var newPart = snapshot.Load(refVessel, false); + refVessel.Parts.Add(newPart); + newPart.transform.position = position; + newPart.transform.rotation = rotation; + newPart.missionID = fromPart.missionID; + newPart.UpdateOrgPosAndRot(newPart.vessel.rootPart); + + if (coupleToPart != null) + { + // Wait for part to initialize and then fire ready event. + Debug.Log("Ready to error" + newPart + srcAttachNodeId + tgtAttachNode); + newPart.StartCoroutine( + WaitAndCouple(newPart, srcAttachNodeId, tgtAttachNode, onPartReady, + createPhysicsless: createPhysicsless)); + } + else + { + // Create new part as a separate vessel. + newPart.StartCoroutine(WaitAndMakeLonePart(newPart, onPartReady)); + } + return newPart; + } + + static IEnumerator WaitAndCouple(Part newPart, string srcAttachNodeId, + AttachNode tgtAttachNode, OnPartReady onPartReady, + bool createPhysicsless = false) + { + var tgtPart = newPart.parent; + if (createPhysicsless) + { + newPart.PhysicsSignificance = 1; // Disable physics on the part. + } + + // Create proper attach nodes. + Debug.Log("Attach new part {0} to {1}: srcNodeId={2}, tgtNode={3}" + + newPart + newPart.vessel + + srcAttachNodeId); + var srcAttachNode = GetAttachNodeById(newPart, srcAttachNodeId); + srcAttachNode.attachedPart = tgtPart; + srcAttachNode.attachedPartId = tgtPart.flightID; + if (tgtAttachNode != null) + { + tgtAttachNode.attachedPart = newPart; + tgtAttachNode.attachedPartId = newPart.flightID; + } + + // When target, source or both are docking ports force them into state PreAttached. It's the + // most safe state that simulates behavior of parts attached in the editor. + var srcDockingNode = GetDockingNode(newPart, attachNodeId: srcAttachNodeId); + if (srcDockingNode != null) + { + // Source part is not yet started. It's functionality is very limited. + srcDockingNode.state = "PreAttached"; + srcDockingNode.dockedPartUId = 0; + srcDockingNode.dockingNodeModuleIndex = 0; + Debug.Log("Force new node {0} to state {1}" + newPart + srcDockingNode.state); + } + var tgtDockingNode = GetDockingNode(tgtPart, attachNode: tgtAttachNode); + if (tgtDockingNode != null) + { + CoupleDockingPortWithPart(tgtDockingNode); + } + + // Wait until part is started. Keep it in position till it happen. + Debug.Log("Wait for part {0} to get alive...", newPart); + newPart.transform.parent = tgtPart.transform; + var relPos = newPart.transform.localPosition; + var relRot = newPart.transform.localRotation; + if (newPart.PhysicsSignificance != 1) + { + // Mangling with colliders on physicsless parts may result in camera effects. + var childColliders = newPart.GetComponentsInChildren(includeInactive: false); + CollisionManager.IgnoreCollidersOnVessel(tgtPart.vessel, childColliders); + } + while (!newPart.started && newPart.State != PartStates.DEAD) + { + yield return new WaitForFixedUpdate(); + if (newPart.rb != null) + { + newPart.rb.position = newPart.parent.transform.TransformPoint(relPos); + newPart.rb.rotation = newPart.parent.transform.rotation * relRot; + newPart.rb.velocity = newPart.parent.Rigidbody.velocity; + newPart.rb.angularVelocity = newPart.parent.Rigidbody.angularVelocity; + } + } + newPart.transform.parent = newPart.transform; + Debug.Log("Part {0} is in state {1}" + newPart + newPart.State); + if (newPart.State == PartStates.DEAD) + { + Debug.Log("Part {0} has died before fully instantiating", newPart); + yield break; + } + + // Complete part initialization. + newPart.Unpack(); + newPart.InitializeModules(); + + // Notify game about a new part that has just "coupled". + GameEvents.onPartCouple.Fire(new GameEvents.FromToAction(newPart, tgtPart)); + tgtPart.vessel.ClearStaging(); + GameEvents.onVesselPartCountChanged.Fire(tgtPart.vessel); + newPart.vessel.checkLanded(); + newPart.vessel.currentStage = StageManager.RecalculateVesselStaging(tgtPart.vessel) + 1; + GameEvents.onVesselWasModified.Fire(tgtPart.vessel); + newPart.CheckBodyLiftAttachment(); + + if (onPartReady != null) + { + onPartReady(newPart); + } + } + } +} diff --git a/BDArmory/Modules/ModuleMovingPart.cs b/BDArmory/Modules/ModuleMovingPart.cs new file mode 100644 index 000000000..0d06b142b --- /dev/null +++ b/BDArmory/Modules/ModuleMovingPart.cs @@ -0,0 +1,95 @@ +using System.Collections; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class ModuleMovingPart : PartModule + { + Transform parentTransform; + [KSPField] public string parentTransformName = string.Empty; + + bool setupComplete; + + Part[] children; + Vector3[] localAnchors; + + public override void OnStart(StartState state) + { + base.OnStart(state); + + if (HighLogic.LoadedSceneIsFlight) + { + if (parentTransformName == string.Empty) + { + enabled = false; + return; + } + + parentTransform = part.FindModelTransform(parentTransformName); + + StartCoroutine(SetupRoutine()); + } + } + + void FixedUpdate() + { + if (setupComplete) + { + UpdateJoints(); + } + } + + IEnumerator SetupRoutine() + { + while (vessel.packed) + { + yield return null; + } + SetupJoints(); + } + + void SetupJoints() + { + children = part.children.ToArray(); + localAnchors = new Vector3[children.Length]; + + for (int i = 0; i < children.Length; i++) + { + children[i].attachJoint.Joint.autoConfigureConnectedAnchor = false; + Vector3 connectedAnchor = children[i].attachJoint.Joint.connectedAnchor; + Vector3 worldAnchor = + children[i].attachJoint.Joint.connectedBody.transform.TransformPoint(connectedAnchor); + Vector3 localAnchor = parentTransform.InverseTransformPoint(worldAnchor); + localAnchors[i] = localAnchor; + } + + setupComplete = true; + } + + void UpdateJoints() + { + for (int i = 0; i < children.Length; i++) + { + if (!children[i]) continue; + + Vector3 newWorldAnchor = parentTransform.TransformPoint(localAnchors[i]); + Vector3 newConnectedAnchor = + children[i].attachJoint.Joint.connectedBody.transform.InverseTransformPoint(newWorldAnchor); + children[i].attachJoint.Joint.connectedAnchor = newConnectedAnchor; + } + } + + void OnGUI() + { + if (setupComplete) + { + for (int i = 0; i < localAnchors.Length; i++) + { + BDGUIUtils.DrawTextureOnWorldPos(parentTransform.TransformPoint(localAnchors[i]), + BDArmorySetup.Instance.greenDotTexture, new Vector2(6, 6), 0); + } + } + } + } +} diff --git a/BDArmory/Modules/ModuleRadar.cs b/BDArmory/Modules/ModuleRadar.cs new file mode 100644 index 000000000..060fcb21a --- /dev/null +++ b/BDArmory/Modules/ModuleRadar.cs @@ -0,0 +1,1144 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using BDArmory.Core; +using BDArmory.Misc; +using BDArmory.Radar; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; +using KSP.Localization; + +namespace BDArmory.Modules +{ + public class ModuleRadar : PartModule + { + #region KSPFields (Part Configuration) + + #region General Configuration + + [KSPField] + public string radarName; + + [KSPField] + public int turretID = 0; + + [KSPField] + public string rotationTransformName = string.Empty; + Transform rotationTransform; + + #endregion General Configuration + + #region Radar Capabilities + + [KSPField] + public int rwrThreatType = 0; //IMPORTANT, configures which type of radar it will show up as on the RWR + public RadarWarningReceiver.RWRThreatTypes rwrType = RadarWarningReceiver.RWRThreatTypes.SAM; + + [KSPField] + public double resourceDrain = 0.825; //resource (EC/sec) usage of active radar + + [KSPField] + public bool omnidirectional = true; //false=boresight only + + [KSPField] + public float directionalFieldOfView = 90; //relevant for omnidirectional only + + [KSPField] + public float boresightFOV = 10; //relevant for boresight only + + [KSPField] + public float scanRotationSpeed = 120; //in degrees per second, relevant for omni and directional + + [KSPField] + public float lockRotationSpeed = 120; //in degrees per second, relevant for omni only + + [KSPField] + public float lockRotationAngle = 4; //??? + + [KSPField] + public bool showDirectionWhileScan = false; //radar can show direction indicator of contacts (false: can show contacts as blocks only) + + [KSPField] + public float multiLockFOV = 30; //?? + + [KSPField] + public float lockAttemptFOV = 2; //?? + + [KSPField] + public bool canScan = true; //radar has detection capabilities + + [KSPField] + public bool canLock = true; //radar has locking/tracking capabilities + + [KSPField] + public int maxLocks = 1; //how many targets can be locked/tracked simultaneously + + [KSPField] + public bool canTrackWhileScan = false; //when tracking/locking, can we still detect/scan? + + [KSPField] + public bool canRecieveRadarData = false; //can radar data be received from friendly sources? + + [KSPField] + public FloatCurve radarDetectionCurve = new FloatCurve(); //FloatCurve defining at what range which RCS size can be detected + + [KSPField] + public FloatCurve radarLockTrackCurve = new FloatCurve(); //FloatCurve defining at what range which RCS size can be locked/tracked + + [KSPField] + public float radarGroundClutterFactor = 0.25f; //Factor defining how effective the radar is for look-down, compensating for ground clutter (0=ineffective, 1=fully effective) + //default to 0.25, so all cross sections of landed/splashed/submerged vessels are reduced to 1/4th, as these vessel usually a quite large + + #endregion Radar Capabilities + + #region Persisted State in flight + + [KSPField(isPersistant = true)] + public string linkedVesselID; + + [KSPField(isPersistant = true)] + public bool radarEnabled; + + [KSPField(isPersistant = true)] + public int rangeIndex = 99; + + [KSPField(isPersistant = true)] + public float currentAngle; + + #endregion Persisted State in flight + + #region DEPRECATED! ->see Radar Capabilities section for new detectionCurve + trackingCurve + + [Obsolete] + [KSPField] + public float minSignalThreshold = 90; + + [Obsolete] + [KSPField] + public float minLockedSignalThreshold = 90; + + #endregion DEPRECATED! ->see Radar Capabilities section for new detectionCurve + trackingCurve + + #endregion KSPFields (Part Configuration) + + #region KSP Events & Actions + + [KSPAction("Toggle Radar")] + public void AGEnable(KSPActionParam param) + { + if (radarEnabled) + { + DisableRadar(); + } + else + { + EnableRadar(); + } + } + + [KSPEvent(active = true, guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_ToggleRadar")]//Toggle Radar + public void Toggle() + { + if (radarEnabled) + { + DisableRadar(); + } + else + { + EnableRadar(); + } + } + + [KSPAction("Target Next")] + public void TargetNext(KSPActionParam param) + { + vesselRadarData.TargetNext(); + } + + [KSPAction("Target Prev")] + public void TargetPrev(KSPActionParam param) + { + vesselRadarData.TargetPrev(); + } + + #endregion KSP Events & Actions + + #region Part members + + //locks + [KSPField(isPersistant = false, guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_CurrentLocks")]//Current Locks + public int currLocks; + + public bool locked + { + get { return currLocks > 0; } + } + + public int currentLocks + { + get { return currLocks; } + } + + private TargetSignatureData[] attemptedLocks; + private List lockedTargets; + + public TargetSignatureData lockedTarget + { + get + { + if (currLocks == 0) return TargetSignatureData.noTarget; + else + { + return lockedTargets[lockedTargetIndex]; + } + } + } + + private int lockedTargetIndex; + + public int currentLockIndex + { + get { return lockedTargetIndex; } + } + + public float radarMinDistanceDetect + { + get { return radarDetectionCurve.minTime; } + } + + //[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "Detection Range")] + public float radarMaxDistanceDetect + { + get { return radarDetectionCurve.maxTime; } + } + + public float radarMinDistanceLockTrack + { + get { return radarLockTrackCurve.minTime; } + } + + //[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "Locking Range")] + public float radarMaxDistanceLockTrack + { + get { return radarLockTrackCurve.maxTime; } + } + + //linked vessels + private List linkedToVessels; + public List availableRadarLinks; + private bool unlinkOnDestroy = true; + + //GUI + private bool drawGUI; + public float signalPersistTime; + public float signalPersistTimeForRwr; + + //scanning + private float currentAngleLock; + public Transform referenceTransform; + private float radialScanDirection = 1; + private float lockScanDirection = 1; + + public bool boresightScan; + + //locking + public float lockScanAngle; + public bool slaveTurrets; + public ModuleTurret lockingTurret; + public bool lockingPitch = true; + public bool lockingYaw = true; + + //vessel + private MissileFire wpmr; + + public MissileFire weaponManager + { + get + { + if (wpmr != null && wpmr.vessel == vessel) return wpmr; + wpmr = null; + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + wpmr = mf.Current; + } + mf.Dispose(); + return wpmr; + } + set { wpmr = value; } + } + + public VesselRadarData vesselRadarData; + private string myVesselID; + + // part state + private bool startupComplete; + public float leftLimit; + public float rightLimit; + private int snapshotTicker; + + #endregion Part members + + void UpdateToggleGuiName() + { + Events["Toggle"].guiName = radarEnabled ? Localizer.Format("#autoLOC_bda_1000000") : Localizer.Format("#autoLOC_bda_1000001"); // #autoLOC_bda_1000000 = Disable Radar // #autoLOC_bda_1000001 = Enable Radar + } + + public void EnsureVesselRadarData() + { + if (vessel == null) return; + //myVesselID = vessel.id.ToString(); + + if (vesselRadarData != null && vesselRadarData.vessel == vessel) return; + vesselRadarData = vessel.gameObject.GetComponent(); + + if (vesselRadarData == null) + { + vesselRadarData = vessel.gameObject.AddComponent(); + vesselRadarData.weaponManager = weaponManager; + } + } + + public void EnableRadar() + { + EnsureVesselRadarData(); + radarEnabled = true; + + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + weaponManager = mf.Current; + if (vesselRadarData) + { + vesselRadarData.weaponManager = mf.Current; + } + break; + } + mf.Dispose(); + + UpdateToggleGuiName(); + vesselRadarData.AddRadar(this); + } + + public void DisableRadar() + { + if (locked) + { + UnlockAllTargets(); + } + + radarEnabled = false; + UpdateToggleGuiName(); + + if (vesselRadarData) + { + vesselRadarData.RemoveRadar(this); + } + + List.Enumerator vrd = linkedToVessels.GetEnumerator(); + while (vrd.MoveNext()) + { + if (vrd.Current == null) continue; + vrd.Current.UnlinkDisabledRadar(this); + } + vrd.Dispose(); + } + + void OnDestroy() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (vesselRadarData) + { + vesselRadarData.RemoveRadar(this); + vesselRadarData.RemoveDataFromRadar(this); + } + + if (linkedToVessels != null) + { + List.Enumerator vrd = linkedToVessels.GetEnumerator(); + while (vrd.MoveNext()) + { + if (vrd.Current == null) continue; + if (unlinkOnDestroy) + { + vrd.Current.UnlinkDisabledRadar(this); + } + else + { + vrd.Current.BeginWaitForUnloadedLinkedRadar(this, myVesselID); + } + } + vrd.Dispose(); + } + } + } + + public override void OnStart(StartState state) + { + base.OnStart(state); + + if (HighLogic.LoadedSceneIsFlight) + { + myVesselID = vessel.id.ToString(); + RadarUtils.SetupResources(); + + if (string.IsNullOrEmpty(radarName)) + { + radarName = part.partInfo.title; + } + + linkedToVessels = new List(); + + signalPersistTime = omnidirectional + ? 360 / (scanRotationSpeed + 5) + : directionalFieldOfView / (scanRotationSpeed + 5); + + rwrType = (RadarWarningReceiver.RWRThreatTypes)rwrThreatType; + if (rwrType == RadarWarningReceiver.RWRThreatTypes.Sonar) + signalPersistTimeForRwr = RadarUtils.ACTIVE_MISSILE_PING_PERISTS_TIME; + else + signalPersistTimeForRwr = signalPersistTime / 2; + + if (rotationTransformName != string.Empty) + { + rotationTransform = part.FindModelTransform(rotationTransformName); + } + + attemptedLocks = new TargetSignatureData[3]; + TargetSignatureData.ResetTSDArray(ref attemptedLocks); + lockedTargets = new List(); + + referenceTransform = (new GameObject()).transform; + referenceTransform.parent = transform; + referenceTransform.localPosition = Vector3.zero; + + List.Enumerator turr = part.FindModulesImplementing().GetEnumerator(); + while (turr.MoveNext()) + { + if (turr.Current == null) continue; + if (turr.Current.turretID != turretID) continue; + lockingTurret = turr.Current; + break; + } + turr.Dispose(); + + //GameEvents.onVesselGoOnRails.Add(OnGoOnRails); //not needed + EnsureVesselRadarData(); + StartCoroutine(StartUpRoutine()); + } + else if (HighLogic.LoadedSceneIsEditor) + { + //Editor only: + List.Enumerator tur = part.FindModulesImplementing().GetEnumerator(); + while (tur.MoveNext()) + { + if (tur.Current == null) continue; + if (tur.Current.turretID != turretID) continue; + lockingTurret = tur.Current; + break; + } + tur.Dispose(); + if (lockingTurret) + { + lockingTurret.Fields["minPitch"].guiActiveEditor = false; + lockingTurret.Fields["maxPitch"].guiActiveEditor = false; + lockingTurret.Fields["yawRange"].guiActiveEditor = false; + } + } + + // check for not updated legacy part: + if ((canScan && (radarMinDistanceDetect == float.MaxValue)) || (canLock && (radarMinDistanceLockTrack == float.MaxValue))) + { + Debug.Log("[BDArmory]: WARNING: " + part.name + " has legacy definition, missing new radarDetectionCurve and radarLockTrackCurve definitions! Please update for the part to be usable!"); + } + } + + /* + void OnGoOnRails(Vessel v) + { + if (v != vessel) return; + unlinkOnDestroy = false; + //myVesselID = vessel.id.ToString(); + } + */ + + IEnumerator StartUpRoutine() + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: StartupRoutine: " + radarName + " enabled: " + radarEnabled); + while (!FlightGlobals.ready || vessel.packed) + { + yield return null; + } + + yield return new WaitForFixedUpdate(); + + if (radarEnabled) + { + EnableRadar(); + } + + yield return null; + + if (!vesselRadarData.hasLoadedExternalVRDs) + { + RecoverLinkedVessels(); + vesselRadarData.hasLoadedExternalVRDs = true; + } + + UpdateToggleGuiName(); + startupComplete = true; + } + + void Update() + { + if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && radarEnabled) + { + if (omnidirectional) + { + referenceTransform.position = part.transform.position; + referenceTransform.rotation = + Quaternion.LookRotation(VectorUtils.GetNorthVector(transform.position, vessel.mainBody), + VectorUtils.GetUpDirection(transform.position)); + } + else + { + referenceTransform.position = part.transform.position; + referenceTransform.rotation = Quaternion.LookRotation(part.transform.up, + VectorUtils.GetUpDirection(referenceTransform.position)); + } + //UpdateInputs(); + } + + drawGUI = (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && radarEnabled && + vessel.isActiveVessel && BDArmorySetup.GAME_UI_ENABLED && !MapView.MapIsEnabled); + } + + void FixedUpdate() + { + if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && startupComplete) + { + if (!vessel.IsControllable && radarEnabled) + { + DisableRadar(); + } + + if (radarEnabled) + { + DrainElectricity(); //physics behaviour, thus moved here from update + + if (locked) + { + for (int i = 0; i < lockedTargets.Count; i++) + { + UpdateLock(i); + } + + if (canTrackWhileScan) + { + Scan(); + } + } + else if (boresightScan) + { + BoresightScan(); + } + else if (canScan) + { + Scan(); + } + } + } + } + + void UpdateSlaveData() + { + if (slaveTurrets && weaponManager) + { + weaponManager.slavingTurrets = true; + if (locked) + { + weaponManager.slavedPosition = lockedTarget.predictedPosition; + weaponManager.slavedVelocity = lockedTarget.velocity; + weaponManager.slavedAcceleration = lockedTarget.acceleration; + weaponManager.slavedTarget = lockedTarget; + } + } + } + + void LateUpdate() + { + if (HighLogic.LoadedSceneIsFlight && (canScan || canLock)) + { + UpdateModel(); + } + } + + void UpdateModel() + { + //model rotation + if (radarEnabled) + { + if (rotationTransform && canScan) + { + Vector3 direction; + if (locked) + { + direction = + Quaternion.AngleAxis(canTrackWhileScan ? currentAngle : lockScanAngle, referenceTransform.up) * + referenceTransform.forward; + } + else + { + direction = Quaternion.AngleAxis(currentAngle, referenceTransform.up) * referenceTransform.forward; + } + + Vector3 localDirection = + Vector3.ProjectOnPlane(rotationTransform.parent.InverseTransformDirection(direction), Vector3.up); + if (localDirection != Vector3.zero) + { + rotationTransform.localRotation = Quaternion.Lerp(rotationTransform.localRotation, + Quaternion.LookRotation(localDirection, Vector3.up), 10 * TimeWarp.fixedDeltaTime); + } + } + + //lock turret + if (lockingTurret && canLock) + { + if (locked) + { + lockingTurret.AimToTarget(lockedTarget.predictedPosition, lockingPitch, lockingYaw); + } + else + { + lockingTurret.ReturnTurret(); + } + } + } + else + { + if (rotationTransform) + { + rotationTransform.localRotation = Quaternion.Lerp(rotationTransform.localRotation, + Quaternion.identity, 5 * TimeWarp.fixedDeltaTime); + } + + if (lockingTurret) + { + lockingTurret.ReturnTurret(); + } + } + } + + void Scan() + { + float angleDelta = scanRotationSpeed * Time.fixedDeltaTime; + RadarUtils.RadarUpdateScanLock(weaponManager, currentAngle, referenceTransform, angleDelta, referenceTransform.position, this, false, ref attemptedLocks); + + if (omnidirectional) + { + currentAngle = Mathf.Repeat(currentAngle + angleDelta, 360); + } + else + { + currentAngle += radialScanDirection * angleDelta; + + if (locked) + { + float targetAngle = VectorUtils.SignedAngle(referenceTransform.forward, + Vector3.ProjectOnPlane(lockedTarget.position - referenceTransform.position, + referenceTransform.up), referenceTransform.right); + leftLimit = Mathf.Clamp(targetAngle - (multiLockFOV / 2), -directionalFieldOfView / 2, + directionalFieldOfView / 2); + rightLimit = Mathf.Clamp(targetAngle + (multiLockFOV / 2), -directionalFieldOfView / 2, + directionalFieldOfView / 2); + + if (radialScanDirection < 0 && currentAngle < leftLimit) + { + currentAngle = leftLimit; + radialScanDirection = 1; + } + else if (radialScanDirection > 0 && currentAngle > rightLimit) + { + currentAngle = rightLimit; + radialScanDirection = -1; + } + } + else + { + if (Mathf.Abs(currentAngle) > directionalFieldOfView / 2) + { + currentAngle = Mathf.Sign(currentAngle) * directionalFieldOfView / 2; + radialScanDirection = -radialScanDirection; + } + } + } + } + + public bool TryLockTarget(Vector3 position) + { + if (!canLock) + { + return false; + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Trying to radar lock target with (" + radarName + ")"); + + if (currentLocks == maxLocks) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: - Failed, this radar already has the maximum allowed targets locked."); + return false; + } + + Vector3 targetPlanarDirection = Vector3.ProjectOnPlane(position - referenceTransform.position, + referenceTransform.up); + float angle = Vector3.Angle(targetPlanarDirection, referenceTransform.forward); + if (referenceTransform.InverseTransformPoint(position).x < 0) + { + angle = -angle; + } + //TargetSignatureData.ResetTSDArray(ref attemptedLocks); + RadarUtils.RadarUpdateScanLock(weaponManager, angle, referenceTransform, lockAttemptFOV, referenceTransform.position, this, true, ref attemptedLocks, signalPersistTime); + + for (int i = 0; i < attemptedLocks.Length; i++) + { + if (attemptedLocks[i].exists && (attemptedLocks[i].predictedPosition - position).sqrMagnitude < 40 * 40) + { + if (!locked && !omnidirectional) + { + float targetAngle = VectorUtils.SignedAngle(referenceTransform.forward, + Vector3.ProjectOnPlane(attemptedLocks[i].position - referenceTransform.position, + referenceTransform.up), referenceTransform.right); + currentAngle = targetAngle; + } + lockedTargets.Add(attemptedLocks[i]); + currLocks = lockedTargets.Count; + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: - Acquired lock on target (" + attemptedLocks[i].vessel?.name + ")"); + + vesselRadarData.AddRadarContact(this, lockedTarget, true); + vesselRadarData.UpdateLockedTargets(); + return true; + } + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: - Failed to lock on target."); + + return false; + } + + void BoresightScan() + { + if (locked) + { + boresightScan = false; + return; + } + + currentAngle = Mathf.Lerp(currentAngle, 0, 0.08f); + RadarUtils.RadarUpdateScanBoresight(new Ray(transform.position, transform.up), boresightFOV, ref attemptedLocks, Time.fixedDeltaTime, this); + + for (int i = 0; i < attemptedLocks.Length; i++) + { + if (!attemptedLocks[i].exists || !(attemptedLocks[i].age < 0.1f)) continue; + TryLockTarget(attemptedLocks[i].predictedPosition); + boresightScan = false; + return; + } + } + + void UpdateLock(int index) + { + TargetSignatureData lockedTarget = lockedTargets[index]; + + Vector3 targetPlanarDirection = + Vector3.ProjectOnPlane(lockedTarget.predictedPosition - referenceTransform.position, + referenceTransform.up); + float lookAngle = Vector3.Angle(targetPlanarDirection, referenceTransform.forward); + if (referenceTransform.InverseTransformPoint(lockedTarget.predictedPosition).x < 0) + { + lookAngle = -lookAngle; + } + + if (omnidirectional) + { + if (lookAngle < 0) lookAngle += 360; + } + + lockScanAngle = lookAngle + currentAngleLock; + if (!canTrackWhileScan && index == lockedTargetIndex) + { + currentAngle = lockScanAngle; + } + float angleDelta = lockRotationSpeed * Time.fixedDeltaTime; + float lockedSignalPersist = lockRotationAngle / lockRotationSpeed; + //RadarUtils.ScanInDirection(lockScanAngle, referenceTransform, angleDelta, referenceTransform.position, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist); + bool radarSnapshot = (snapshotTicker > 30); + if (radarSnapshot) + { + snapshotTicker = 0; + } + else + { + snapshotTicker++; + } + //RadarUtils.ScanInDirection (new Ray (referenceTransform.position, lockedTarget.predictedPosition - referenceTransform.position), lockRotationAngle * 2, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist, true, rwrType, radarSnapshot); + + if ( + Vector3.Angle(lockedTarget.position - referenceTransform.position, + this.lockedTarget.position - referenceTransform.position) > multiLockFOV / 2) + { + UnlockTargetAt(index, true); + return; + } + + RadarUtils.RadarUpdateLockTrack( + new Ray(referenceTransform.position, lockedTarget.predictedPosition - referenceTransform.position), + lockedTarget.predictedPosition, lockRotationAngle * 2, this, lockedSignalPersist, true, index, lockedTarget.vessel); + + //if still failed or out of FOV, unlock. + if (!lockedTarget.exists || + (!omnidirectional && + Vector3.Angle(lockedTarget.position - referenceTransform.position, transform.up) > + directionalFieldOfView / 2)) + { + //UnlockAllTargets(); + UnlockTargetAt(index, true); + return; + } + + //unlock if over-jammed + // MOVED TO RADARUTILS! + + //cycle scan direction + if (index == lockedTargetIndex) + { + currentAngleLock += lockScanDirection * angleDelta; + if (Mathf.Abs(currentAngleLock) > lockRotationAngle / 2) + { + currentAngleLock = Mathf.Sign(currentAngleLock) * lockRotationAngle / 2; + lockScanDirection = -lockScanDirection; + } + } + } + + public void UnlockAllTargets() + { + if (!locked) return; + + lockedTargets.Clear(); + currLocks = 0; + lockedTargetIndex = 0; + + if (vesselRadarData) + { + vesselRadarData.UnlockAllTargetsOfRadar(this); + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Radar Targets were cleared (" + radarName + ")."); + } + + public void SetActiveLock(TargetSignatureData target) + { + for (int i = 0; i < lockedTargets.Count; i++) + { + if (target.vessel == lockedTargets[i].vessel) + { + lockedTargetIndex = i; + return; + } + } + } + + public void UnlockTargetAt(int index, bool tryRelock = false) + { + Vessel rVess = lockedTargets[index].vessel; + + if (tryRelock) + { + UnlockTargetAt(index, false); + if (rVess) + { + StartCoroutine(RetryLockRoutine(rVess)); + } + return; + } + + lockedTargets.RemoveAt(index); + currLocks = lockedTargets.Count; + if (lockedTargetIndex > index) + { + lockedTargetIndex--; + } + + lockedTargetIndex = Mathf.Clamp(lockedTargetIndex, 0, currLocks - 1); + lockedTargetIndex = Mathf.Max(lockedTargetIndex, 0); + + if (vesselRadarData) + { + //vesselRadarData.UnlockTargetAtPosition(position); + vesselRadarData.RemoveVesselFromTargets(rVess); + } + } + + IEnumerator RetryLockRoutine(Vessel v) + { + yield return null; + vesselRadarData.TryLockTarget(v); + } + + public void UnlockTargetVessel(Vessel v) + { + for (int i = 0; i < lockedTargets.Count; i++) + { + if (lockedTargets[i].vessel == v) + { + UnlockTargetAt(i); + return; + } + } + } + + void SlaveTurrets() + { + List.Enumerator mtc = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + if (mtc.Current == null) continue; + mtc.Current.slaveTurrets = false; + } + mtc.Dispose(); + + List.Enumerator rad = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rad.MoveNext()) + { + if (rad.Current == null) continue; + rad.Current.slaveTurrets = false; + } + rad.Dispose(); + + slaveTurrets = true; + } + + void UnslaveTurrets() + { + List.Enumerator mtc = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + if (mtc.Current == null) continue; + mtc.Current.slaveTurrets = false; + } + + List.Enumerator rad = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rad.MoveNext()) + { + if (rad.Current == null) continue; + rad.Current.slaveTurrets = false; + } + + if (weaponManager) + { + weaponManager.slavingTurrets = false; + } + + slaveTurrets = false; + } + + public void UpdateLockedTargetInfo(TargetSignatureData newData) + { + int index = -1; + for (int i = 0; i < lockedTargets.Count; i++) + { + if (lockedTargets[i].vessel != newData.vessel) continue; + index = i; + break; + } + + if (index >= 0) + { + lockedTargets[index] = newData; + } + } + + public void ReceiveContactData(TargetSignatureData contactData, bool _locked) + { + if (vesselRadarData) + { + vesselRadarData.AddRadarContact(this, contactData, _locked); + } + + List.Enumerator vrd = linkedToVessels.GetEnumerator(); + while (vrd.MoveNext()) + { + if (vrd.Current == null) continue; + if (vrd.Current.canReceiveRadarData && vrd.Current.vessel != contactData.vessel) + { + vrd.Current.AddRadarContact(this, contactData, _locked); + } + } + vrd.Dispose(); + } + + public void AddExternalVRD(VesselRadarData vrd) + { + if (!linkedToVessels.Contains(vrd)) + { + linkedToVessels.Add(vrd); + } + } + + public void RemoveExternalVRD(VesselRadarData vrd) + { + linkedToVessels.Remove(vrd); + } + + void OnGUI() + { + if (drawGUI) + { + if (boresightScan) + { + BDGUIUtils.DrawTextureOnWorldPos(transform.position + (3500 * transform.up), + BDArmorySetup.Instance.dottedLargeGreenCircle, new Vector2(156, 156), 0); + } + } + } + + public void RecoverLinkedVessels() + { + string[] vesselIDs = linkedVesselID.Split(new char[] { ',' }); + for (int i = 0; i < vesselIDs.Length; i++) + { + StartCoroutine(RecoverLinkedVesselRoutine(vesselIDs[i])); + } + } + + IEnumerator RecoverLinkedVesselRoutine(string vesselID) + { + while (true) + { + List.Enumerator v = BDATargetManager.LoadedVessels.GetEnumerator(); + while (v.MoveNext()) + { + if (v.Current == null || !v.Current.loaded || v.Current == vessel) continue; + if (v.Current.id.ToString() != vesselID) continue; + VesselRadarData vrd = v.Current.gameObject.GetComponent(); + if (!vrd) continue; + StartCoroutine(RelinkVRDWhenReadyRoutine(vrd)); + yield break; + } + v.Dispose(); + + yield return new WaitForSeconds(0.5f); + } + } + + IEnumerator RelinkVRDWhenReadyRoutine(VesselRadarData vrd) + { + while (!vrd.radarsReady || vrd.vessel.packed) + { + yield return null; + } + yield return null; + vesselRadarData.LinkVRD(vrd); + Debug.Log("[BDArmory]: Radar data link recovered: Local - " + vessel.vesselName + ", External - " + + vrd.vessel.vesselName); + } + + public string getRWRType(int i) + { + switch (i) + { + case 0: + return Localizer.Format("#autoLOC_bda_1000002"); // #autoLOC_bda_1000002 = SAM + + case 1: + return Localizer.Format("#autoLOC_bda_1000003"); // #autoLOC_bda_1000003 = FIGHTER + + case 2: + return Localizer.Format("#autoLOC_bda_1000004"); // #autoLOC_bda_1000004 = AWACS + + case 3: + case 4: + return Localizer.Format("#autoLOC_bda_1000005"); // #autoLOC_bda_1000005 = MISSILE + + case 5: + return Localizer.Format("#autoLOC_bda_1000006"); // #autoLOC_bda_1000006 = DETECTION + + case 6: + return Localizer.Format("#autoLOC_bda_1000017"); // #autoLOC_bda_1000017 = SONAR + } + return Localizer.Format("#autoLOC_bda_1000007"); // #autoLOC_bda_1000007 = UNKNOWN + //{SAM = 0, Fighter = 1, AWACS = 2, MissileLaunch = 3, MissileLock = 4, Detection = 5, Sonar = 6} + } + + // RMB info in editor + public override string GetInfo() + { + bool isLinkOnly = (canRecieveRadarData && !canScan && !canLock); + + StringBuilder output = new StringBuilder(); + output.Append(Environment.NewLine); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000008", (isLinkOnly ? Localizer.Format("#autoLOC_bda_1000018") : omnidirectional ? Localizer.Format("#autoLOC_bda_1000019") : Localizer.Format("#autoLOC_bda_1000020")))); + + output.AppendLine(Localizer.Format("#autoLOC_bda_1000021", resourceDrain)); + if (!isLinkOnly) + { + output.AppendLine(Localizer.Format("#autoLOC_bda_1000022", directionalFieldOfView)); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000023", getRWRType(rwrThreatType))); + + output.Append(Environment.NewLine); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000024")); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000025", canScan)); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000026", canTrackWhileScan)); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000027", canLock)); + if (canLock) + { + output.AppendLine(Localizer.Format("#autoLOC_bda_1000028", maxLocks)); + } + output.AppendLine(Localizer.Format("#autoLOC_bda_1000029", canRecieveRadarData)); + + output.Append(Environment.NewLine); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000030")); + + if (canScan) + output.AppendLine(Localizer.Format("#autoLOC_bda_1000031", radarDetectionCurve.Evaluate(radarMaxDistanceDetect), radarMaxDistanceDetect)); + else + output.AppendLine(Localizer.Format("#autoLOC_bda_1000032")); + if (canLock) + output.AppendLine(Localizer.Format("#autoLOC_bda_1000033", radarLockTrackCurve.Evaluate(radarMaxDistanceLockTrack), radarMaxDistanceLockTrack)); + else + output.AppendLine(Localizer.Format("#autoLOC_bda_1000034")); + output.AppendLine(Localizer.Format("#autoLOC_bda_1000035", radarGroundClutterFactor)); + } + + return output.ToString(); + } + + void DrainElectricity() + { + if (resourceDrain <= 0) + { + return; + } + + double drainAmount = resourceDrain * TimeWarp.fixedDeltaTime; + double chargeAvailable = part.RequestResource("ElectricCharge", drainAmount, ResourceFlowMode.ALL_VESSEL); + if (chargeAvailable < drainAmount * 0.95f) + { + ScreenMessages.PostScreenMessage(Localizer.Format("#autoLOC_bda_1000016"), 5.0f, ScreenMessageStyle.UPPER_CENTER); // #autoLOC_bda_1000016 = Radar Requires EC + DisableRadar(); + } + } + } +} diff --git a/BDArmory/Modules/ModuleReactiveArmor.cs b/BDArmory/Modules/ModuleReactiveArmor.cs new file mode 100644 index 000000000..8123818dc --- /dev/null +++ b/BDArmory/Modules/ModuleReactiveArmor.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using BDArmory.Core.Module; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class ModuleReactiveArmor : PartModule + { + //[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Damage Percentage Threshold"), + // UI_FloatRange(controlEnabled = true, scene = UI_Scene.All, minValue = 0f, maxValue = 100f, stepIncrement = 1f)] + public float DAMAGEMODIFIER1 = 75; + + //[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Armor Percentage Threshold"), + // UI_FloatRange(controlEnabled = true, scene = UI_Scene.All, minValue = 0f, maxValue = 100f, stepIncrement = 1f)] + public float ARMORMODIFIER1 = 75; + + //[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Damage Modifer [Stage 2]"), + // UI_FloatRange(controlEnabled = true, scene = UI_Scene.All, minValue = 0f, maxValue = 100f, stepIncrement = 1f)] + public float DAMAGEMODIFIER2 = 35; + + //[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Armor Modifer [Stage 2]"), + // UI_FloatRange(controlEnabled = true, scene = UI_Scene.All, minValue = 0f, maxValue = 100f, stepIncrement = 1f)] + public float ARMORMODIFIER2 = 35; + + public bool underAttack = false; + private float partHPmax = 0.0f; + private float partHPtotal = 0.0f; + private float partArmorMax = 0.0f; + private float partArmorTotal = 0.0f; + private double stage = 1; + + + private HitpointTracker hp; + + private HitpointTracker GetHP() + { + HitpointTracker hp = null; + + hp = part.FindModuleImplementing(); + + return hp; + } + + public override void OnStart(StartState state) + { + initializeData(); + + useTextureAll(false); + + if (HighLogic.LoadedSceneIsFlight) + { + Setup(); + } + base.OnStart(state); + } + + public void Update() + { + if (!HighLogic.LoadedSceneIsFlight) return; + if (stage == 1) + { + CheckPart(); + } + } + + private void ScreenMsg(string msg) + { + ScreenMessages.PostScreenMessage(new ScreenMessage(msg, 0.005f, ScreenMessageStyle.UPPER_RIGHT)); + } + + private void Setup() + { + hp = GetHP(); + + partHPmax = hp.maxHitPoints; + partHPtotal = hp.Hitpoints; + partArmorMax = hp.ArmorThickness; + partArmorTotal = hp.Armor; + } + + public void CheckPart() + { + hp = GetHP(); + partHPtotal = hp.Hitpoints; + partArmorTotal = hp.Armor; + + if (stage != 1 || (!(partHPtotal <= partHPmax * DAMAGEMODIFIER1 / 100) && + !(partArmorTotal <= partArmorMax * ARMORMODIFIER1 / 100))) return; + stage = 2; + hp.Armor = ARMORMODIFIER2 * partArmorMax / 100; + hp.ArmorThickness = hp.Armor; + hp.Hitpoints = DAMAGEMODIFIER2 * partHPmax / 100; + hp.maxHitPoints = hp.Hitpoints; + + partHPmax = hp.maxHitPoints; + partHPtotal = hp.Hitpoints; + partArmorMax = hp.ArmorThickness; + partArmorTotal = hp.Armor; + + nextTextureEvent(); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + [KSPField] + public string currentTextureName = string.Empty; + + [KSPField] + public string textureRootFolder = string.Empty; + + [KSPField] + public string objectNames = string.Empty; + + [KSPField] + public string textureNames = string.Empty; + + [KSPField] + public string mapNames = string.Empty; + + [KSPField] + public string textureDisplayNames = "Default"; + + [KSPField(isPersistant = true)] + public int selectedTexture = 0; + + [KSPField(isPersistant = true)] + public string selectedTextureURL = string.Empty; + + [KSPField(isPersistant = true)] + public string selectedMapURL = string.Empty; + + [KSPField] + public string additionalMapType = "_BumpMap"; + + [KSPField] + public bool mapIsNormal = true; + + private List targetObjectTransforms = new List(); + private List> targetMats = new List>(); + private List texList = new List(); + private List mapList = new List(); + private List objectList = new List(); + private List textureDisplayList = new List(); + + private bool initialized = false; + + List ListChildren(Transform a) + { + List childList = new List(); + foreach (Transform b in a) + { + childList.Add(b); + childList.AddRange(ListChildren(b)); + } + return childList; + } + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_NextTexture")]//Next Texture + public void nextTextureEvent() + { + selectedTexture++; + if (selectedTexture >= texList.Count && selectedTexture >= mapList.Count) + selectedTexture = 0; + useTextureAll(true); + } + + public void useTextureAll(bool calledByPlayer) + { + applyTexToPart(calledByPlayer); + } + + private void applyTexToPart(bool calledByPlayer) + { + initializeData(); + foreach (List matList in targetMats) + { + foreach (Material mat in matList) + { + useTextureOrMap(mat); + } + } + } + + public void useTextureOrMap(Material targetMat) + { + if (targetMat == null) return; + useTexture(targetMat); + + useMap(targetMat); + } + + private void useMap(Material targetMat) + { + if (mapList.Count <= selectedTexture) return; + if (GameDatabase.Instance.ExistsTexture(mapList[selectedTexture])) + { + targetMat.SetTexture(additionalMapType, GameDatabase.Instance.GetTexture(mapList[selectedTexture], mapIsNormal)); + selectedMapURL = mapList[selectedTexture]; + + if (selectedTexture < textureDisplayList.Count && texList.Count == 0) + { + currentTextureName = textureDisplayList[selectedTexture]; + } + } + } + + private void useTexture(Material targetMat) + { + if (texList.Count <= selectedTexture) return; + if (!GameDatabase.Instance.ExistsTexture(texList[selectedTexture])) return; + targetMat.mainTexture = GameDatabase.Instance.GetTexture(texList[selectedTexture], false); + selectedTextureURL = texList[selectedTexture]; + + currentTextureName = selectedTexture > textureDisplayList.Count - 1 ? + getTextureDisplayName(texList[selectedTexture]) : + textureDisplayList[selectedTexture]; + } + + private string getTextureDisplayName(string longName) + { + string[] splitString = longName.Split('/'); + return splitString[splitString.Length - 1]; + } + + private void initializeData() + { + if (initialized) return; + objectList = parseNames(objectNames, true); + texList = parseNames(textureNames, true, true, textureRootFolder); + mapList = parseNames(mapNames, true, true, textureRootFolder); + textureDisplayList = parseNames(textureDisplayNames); + + foreach (string targetObjectName in objectList) + { + Transform[] targetObjectTransformArray = part.FindModelTransforms(targetObjectName); + List matList = new List(); + foreach (Transform t in targetObjectTransformArray) + { + if (t == null || t.gameObject.GetComponent() == null) continue; + Material targetMat = t.gameObject.GetComponent().material; + if (targetMat == null) continue; + if (!matList.Contains(targetMat)) + { + matList.Add(targetMat); + } + } + targetMats.Add(matList); + } + initialized = true; + } + + ///////////////////////////////////////////////////////////////////// + + public static List parseNames(string names) + { + return parseNames(names, false, true, string.Empty); + } + + public static List parseNames(string names, bool replaceBackslashErrors) + { + return parseNames(names, replaceBackslashErrors, true, string.Empty); + } + + public static List parseNames(string names, bool replaceBackslashErrors, bool trimWhiteSpace, string prefix) + { + List source = names.Split(';').ToList(); + for (int i = source.Count - 1; i >= 0; i--) + { + if (source[i] == string.Empty) + { + source.RemoveAt(i); + } + } + if (trimWhiteSpace) + { + for (int i = 0; i < source.Count; i++) + { + source[i] = source[i].Trim(' '); + } + } + if (prefix != string.Empty) + { + for (int i = 0; i < source.Count; i++) + { + source[i] = prefix + source[i]; + } + } + if (replaceBackslashErrors) + { + for (int i = 0; i < source.Count; i++) + { + source[i] = source[i].Replace('\\', '/'); + } + } + return source.ToList(); + } + + public static List parseIntegers(string stringOfInts) + { + List newIntList = new List(); + string[] valueArray = stringOfInts.Split(';'); + for (int i = 0; i < valueArray.Length; i++) + { + int newValue = 0; + if (int.TryParse(valueArray[i], out newValue)) + { + newIntList.Add(newValue); + } + else + { + Debug.Log("invalid integer: " + valueArray[i]); + } + } + return newIntList; + } + } +} diff --git a/BDArmory/Modules/ModuleSpaceRadar.cs b/BDArmory/Modules/ModuleSpaceRadar.cs new file mode 100644 index 000000000..734eddeb9 --- /dev/null +++ b/BDArmory/Modules/ModuleSpaceRadar.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace BDArmory.Modules +{ + public class ModuleSpaceRadar : ModuleRadar + { + public void Update() // runs every frame + { + if (HighLogic.LoadedSceneIsFlight) // if in the flight scene + { + UpdateRadar(); // run the UpdateRadar code + } + } + + // This code determines if the radar is below the cutoff altitude and if so then + // it disables the radar ... private so that it cannot be accessed by any other code + private void UpdateRadar() + { + if (vessel.atmDensity >= 0.007) // below an atm density of 0.007 the radar will not work + { + List radarParts = new List(200); // creates a list of parts with this module + + foreach (Part p in vessel.Parts) // checks each part in the vessel + { + radarParts.AddRange(p.FindModulesImplementing()); // adds the part to the list if this module is present in the part + } + foreach (ModuleSpaceRadar radarPart in radarParts) // for each of the parts in the list do the following + { + if (radarPart != null && radarPart.radarEnabled) + { + DisableRadar(); // disable the radar + } + } + } + } + } +} diff --git a/BDArmory/Modules/ModuleTargetingCamera.cs b/BDArmory/Modules/ModuleTargetingCamera.cs new file mode 100644 index 000000000..bfb2b5434 --- /dev/null +++ b/BDArmory/Modules/ModuleTargetingCamera.cs @@ -0,0 +1,1574 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.CounterMeasure; +using BDArmory.Misc; +using BDArmory.Parts; +using BDArmory.Radar; +using BDArmory.UI; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace BDArmory.Modules +{ + public class ModuleTargetingCamera : PartModule + { + [KSPField] + public string cameraTransformName; + public Transform cameraParentTransform; + + [KSPField] + public string eyeHolderTransformName; + Transform eyeHolderTransform; + + [KSPField] + public float maxRayDistance = 15500; + + [KSPField] + public float gimbalLimit = 120; + public bool gimbalLimitReached; + + [KSPField] + public bool rollCameraModel = false; + + [KSPField(isPersistant = true)] + public bool cameraEnabled; + + float fov + { + get + { + return zoomFovs[currentFovIndex]; + } + } + + [KSPField] + public string zoomFOVs = "40,15,3,1"; + float[] zoomFovs; + + [KSPField(isPersistant = true)] + public int currentFovIndex; + + [KSPField(isPersistant = true)] + public bool slaveTurrets; + + [KSPField(isPersistant = true)] + public bool CoMLock; + + public bool radarLock; + + + [KSPField(isPersistant = true)] + public bool groundStabilized; + + /// + /// Point on surface that camera is focused and stabilized on. + /// + public Vector3 groundTargetPosition; + + [KSPField(isPersistant = true)] + public double savedLat; + + [KSPField(isPersistant = true)] + public double savedLong; + + [KSPField(isPersistant = true)] + public double savedAlt; + + public Vector3 bodyRelativeGTP + { + get + { + return new Vector3d(savedLat, savedLong, savedAlt); + } + + set + { + savedLat = value.x; + savedLong = value.y; + savedAlt = value.z; + } + } + + bool resetting; + + public bool surfaceDetected; + + /// + /// Point where camera is focused, regardless of whether surface is detected or not. + /// + public Vector3 targetPointPosition; + + [KSPField(isPersistant = true)] + public bool nvMode; + + //GUI + public static ModuleTargetingCamera activeCam; + public static bool camRectInitialized; + public static bool windowIsOpen; + private static float camImageSize = 360; + private static float adjCamImageSize = 360; + internal static bool ResizingWindow; + internal static bool SlewingMouseCam; + internal static bool ZoomKeysSet; + internal static bool isZooming; + internal static bool wasZooming; + + internal static bool SlewingButtonCam; + float finalSlewSpeed; + Vector2 slewInput = Vector2.zero; + + private static float gap = 2; + private static float buttonHeight = 18; + private static float controlsStartY = 22; + private static float windowWidth = adjCamImageSize + (3 * buttonHeight) + 16 + 2 * gap; + private static float windowHeight = adjCamImageSize + 23; + private AxisBinding_Single ZoomKeyP; + private AxisBinding_Single ZoomKeyS; + private AxisBinding_Single NoZoomKeyP; + private AxisBinding_Single NoZoomKeyS; + + Texture2D riTex; + + Texture2D rollIndicatorTexture + { + get + { + if (!riTex) + { + riTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/rollIndicator", false); + } + return riTex; + } + } + + Texture2D rrTex; + + Texture2D rollReferenceTexture + { + get + { + if (!rrTex) + { + rrTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/rollReference", false); + } + return rrTex; + } + } + + private MissileFire wpmr; + + public MissileFire weaponManager + { + get + { + if (wpmr == null || wpmr.vessel != vessel) + { + wpmr = null; + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current) + wpmr = mf.Current; + } + mf.Dispose(); + } + + return wpmr; + } + } + + [KSPEvent(guiName = "#LOC_BDArmory_Enable", guiActive = true, guiActiveEditor = false)]//Enable + public void EnableButton() + { + EnableCamera(); + } + + [KSPAction("Enable")] + public void AGEnable(KSPActionParam param) + { + EnableCamera(); + } + + public void ToggleCamera() + { + if (cameraEnabled) + { + DisableCamera(); + } + else + { + EnableCamera(); + } + } + + public void EnableCamera() + { + if (!TargetingCamera.Instance) + { + Debug.Log("Tried to enable targeting camera, but camera instance is null."); + return; + } + if (vessel.isActiveVessel) + { + activeCam = this; + windowIsOpen = true; + TargetingCamera.Instance.EnableCamera(cameraParentTransform); + TargetingCamera.Instance.nvMode = nvMode; + TargetingCamera.Instance.SetFOV(fov); + ResizeTargetWindow(); + } + + cameraEnabled = true; + + if (weaponManager) + { + weaponManager.mainTGP = this; + } + + BDATargetManager.RegisterLaserPoint(this); + } + + public void DisableCamera() + { + cameraEnabled = false; + groundStabilized = false; + + if (slaveTurrets) + { + UnslaveTurrets(); + } + //StopResetting(); + + if (vessel.isActiveVessel) + { + if (!TargetingCamera.Instance) + { + Debug.Log("Tried to disable targeting camera, but camera instance is null."); + return; + } + + TargetingCamera.Instance.DisableCamera(); + if (activeCam == this) + { + activeCam = FindNextActiveCamera(); + if (!activeCam) + { + windowIsOpen = false; + } + } + else + { + windowIsOpen = false; + } + } + BDATargetManager.ActiveLasers.Remove(this); + + if (weaponManager && weaponManager.mainTGP == this) + { + weaponManager.mainTGP = FindNextActiveCamera(); + } + } + + ModuleTargetingCamera FindNextActiveCamera() + { + List.Enumerator mtc = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + if (mtc.Current && mtc.Current.cameraEnabled) + { + mtc.Current.EnableCamera(); + return mtc.Current; + } + } + mtc.Dispose(); + + return null; + } + + public override void OnAwake() + { + base.OnAwake(); + + if (HighLogic.LoadedSceneIsFlight) + { + if (!TargetingCamera.Instance) + { + (new GameObject("TargetingCameraObject")).AddComponent(); + } + } + } + + public override void OnStart(StartState state) + { + base.OnStart(state); + ZoomKeyP = GameSettings.AXIS_MOUSEWHEEL.primary; + ZoomKeyS = GameSettings.AXIS_MOUSEWHEEL.secondary; + NoZoomKeyP = new AxisBinding_Single(); + NoZoomKeyS = new AxisBinding_Single(); + + if (HighLogic.LoadedSceneIsFlight) + { + //GUI setup + if (!camRectInitialized) + { + BDArmorySetup.WindowRectTargetingCam = new Rect(Screen.width - windowWidth, Screen.height - windowHeight, windowWidth, windowHeight); + camRectInitialized = true; + } + + cameraParentTransform = part.FindModelTransform(cameraTransformName); + + eyeHolderTransform = part.FindModelTransform(eyeHolderTransformName); + + ParseFovs(); + UpdateSlewRate(); + + GameEvents.onVesselCreate.Add(Disconnect); + + if (cameraEnabled) + { + Debug.Log("[BDArmory]: saved gtp: " + bodyRelativeGTP); + DelayedEnable(); + } + } + } + + void Disconnect(Vessel v) + { + if (weaponManager && vessel) + { + if (weaponManager.vessel != vessel) + { + if (slaveTurrets) + { + weaponManager.slavingTurrets = false; + } + } + } + } + + public void DelayedEnable() + { + StartCoroutine(DelayedEnableRoutine()); + } + + bool delayedEnabling; + + IEnumerator DelayedEnableRoutine() + { + if (delayedEnabling) yield break; + delayedEnabling = true; + + Vector3d savedGTP = bodyRelativeGTP; + Debug.Log("[BDArmory]: saved gtp: " + Misc.Misc.FormattedGeoPos(savedGTP, true)); + Debug.Log("[BDArmory]: groundStabilized: " + groundStabilized); + + while (TargetingCamera.Instance == null) + { + yield return null; + } + while (!FlightGlobals.ready) + { + yield return null; + } + while (FlightCamera.fetch == null) + { + yield return null; + } + while (FlightCamera.fetch.mainCamera == null) + { + yield return null; + } + while (vessel.packed) + { + yield return null; + } + + while (vessel.mainBody == null) + { + yield return null; + } + + EnableCamera(); + if (groundStabilized) + { + Debug.Log("[BDArmory]: Camera delayed enabled"); + groundTargetPosition = VectorUtils.GetWorldSurfacePostion(savedGTP, vessel.mainBody);// vessel.mainBody.GetWorldSurfacePosition(bodyRelativeGTP.x, bodyRelativeGTP.y, bodyRelativeGTP.z); + Vector3 lookVector = groundTargetPosition - cameraParentTransform.position; + PointCameraModel(lookVector); + GroundStabilize(); + } + delayedEnabling = false; + + Debug.Log("[BDArmory]: post load saved gtp: " + bodyRelativeGTP); + } + + void PointCameraModel(Vector3 lookVector) + { + Vector3 worldUp = VectorUtils.GetUpDirection(cameraParentTransform.position); + if (rollCameraModel) + { + cameraParentTransform.rotation = Quaternion.LookRotation(lookVector, worldUp); + } + else + { + Vector3 camUp = cameraParentTransform.up; + if (eyeHolderTransform) camUp = Vector3.Cross(cameraParentTransform.forward, eyeHolderTransform.right); + cameraParentTransform.rotation = Quaternion.LookRotation(lookVector, camUp); + if (vessel.isActiveVessel && activeCam == this && TargetingCamera.cameraTransform) + { + TargetingCamera.cameraTransform.rotation = Quaternion.LookRotation(cameraParentTransform.forward, worldUp); + } + } + } + + void Update() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (cameraEnabled && TargetingCamera.ReadyForUse && vessel.IsControllable) + { + if (delayedEnabling) return; + + if (!TargetingCamera.Instance || FlightGlobals.currentMainBody == null) + { + return; + } + + if (activeCam == this) + { + if (zoomFovs != null) + { + TargetingCamera.Instance.SetFOV(fov); + } + } + + if (radarLock) + { + UpdateRadarLock(); + } + + if (groundStabilized) + { + groundTargetPosition = VectorUtils.GetWorldSurfacePostion(bodyRelativeGTP, vessel.mainBody);//vessel.mainBody.GetWorldSurfacePosition(bodyRelativeGTP.x, bodyRelativeGTP.y, bodyRelativeGTP.z); + Vector3 lookVector = groundTargetPosition - cameraParentTransform.position; + //cameraParentTransform.rotation = Quaternion.LookRotation(lookVector); + PointCameraModel(lookVector); + } + + Vector3 lookDirection = cameraParentTransform.forward; + if (Vector3.Angle(lookDirection, cameraParentTransform.parent.forward) > gimbalLimit) + { + lookDirection = Vector3.RotateTowards(cameraParentTransform.transform.parent.forward, lookDirection, gimbalLimit * Mathf.Deg2Rad, 0); + gimbalLimitReached = true; + } + else + { + gimbalLimitReached = false; + } + + if (!groundStabilized || gimbalLimitReached) + { + PointCameraModel(lookDirection); + } + + if (eyeHolderTransform) + { + Vector3 projectedForward = Vector3.ProjectOnPlane(cameraParentTransform.forward, eyeHolderTransform.parent.up); + if (projectedForward != Vector3.zero) + { + eyeHolderTransform.rotation = Quaternion.LookRotation(projectedForward, eyeHolderTransform.parent.up); + } + } + + UpdateControls(); + UpdateSlaveData(); + } + } + } + + public override void OnFixedUpdate() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (cameraEnabled && !vessel.packed && !vessel.IsControllable) + { + DisableCamera(); + } + } + } + + void FixedUpdate() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (delayedEnabling) return; + + if (cameraEnabled) + { + GetHitPoint(); + } + } + } + + void UpdateKeyInputs() + { + if (!vessel.isActiveVessel) + { + return; + } + + if (BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_LEFT)) + { + slewInput.x = -1; + } + else if (BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_RIGHT)) + { + slewInput.x = 1; + } + + if (BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_UP)) + { + slewInput.y = 1; + } + else if (BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_DOWN)) + { + slewInput.y = -1; + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_IN)) + { + ZoomIn(); + } + else if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_OUT)) + { + ZoomOut(); + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_LOCK)) + { + if (groundStabilized) + { + ClearTarget(); + } + else + { + GroundStabilize(); + } + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_NV)) + { + ToggleNV(); + } + + if (groundStabilized && BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_SEND_GPS)) + { + SendGPS(); + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_COM)) + { + CoMLock = !CoMLock; + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_RADAR)) + { + radarLock = !radarLock; + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_TURRETS)) + { + if (slaveTurrets) + { + UnslaveTurrets(); + } + else + { + SlaveTurrets(); + } + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_TO_GPS)) + { + PointToGPSTarget(); + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_RESET)) + { + ResetCameraButton(); + } + } + + void ToggleNV() + { + nvMode = !nvMode; + TargetingCamera.Instance.nvMode = nvMode; + } + + void UpdateControls() + { + UpdateKeyInputs(); + UpdateSlewRate(); + if (slewInput != Vector2.zero) + { + SlewCamera(slewInput); + } + slewInput = Vector2.zero; + } + + void UpdateSlewRate() + { + if (SlewingButtonCam) + { + finalSlewSpeed = Mathf.Clamp(finalSlewSpeed + (0.5f * (fov / 60)), 0, 80 * fov / 60); + SlewingButtonCam = false; + } + else + { + finalSlewSpeed = 15 * fov / 60; + } + } + + void UpdateRadarLock() + { + if (weaponManager && weaponManager.vesselRadarData && weaponManager.vesselRadarData.locked) + { + RadarDisplayData tgt = weaponManager.vesselRadarData.lockedTargetData; + Vector3 radarTargetPos = tgt.targetData.predictedPosition; + Vector3 targetDirection = radarTargetPos - cameraParentTransform.position; + + //Quaternion lookRotation = Quaternion.LookRotation(radarTargetPos-cameraParentTransform.position, VectorUtils.GetUpDirection(cameraParentTransform.position)); + if (Vector3.Angle(radarTargetPos - cameraParentTransform.position, cameraParentTransform.forward) < 0.5f) + { + //cameraParentTransform.rotation = lookRotation; + if (tgt.vessel) + { + targetDirection = ((tgt.vessel.CoM) - cameraParentTransform.transform.position); + } + PointCameraModel(targetDirection); + GroundStabilize(); + } + else + { + if (groundStabilized) + { + ClearTarget(); + } + //lookRotation = Quaternion.RotateTowards(cameraParentTransform.rotation, lookRotation, 120*Time.fixedDeltaTime); + Vector3 rotateTwdDirection = Vector3.RotateTowards(cameraParentTransform.forward, targetDirection, 1200 * Time.fixedDeltaTime * Mathf.Deg2Rad, 0); + PointCameraModel(rotateTwdDirection); + } + } + else + { + //radarLock = false; + } + } + + void OnGUI() + { + if (Event.current.type == EventType.MouseUp) + { + if (ResizingWindow) ResizingWindow = false; + if (SlewingMouseCam) SlewingMouseCam = false; + } + + if (!wasZooming && isZooming) + { + wasZooming = true; + SetZoomKeys(); + } + + if (!isZooming && wasZooming) + { + wasZooming = false; + ResetZoomKeys(); + } + + if (HighLogic.LoadedSceneIsFlight && !MapView.MapIsEnabled && BDArmorySetup.GAME_UI_ENABLED && !delayedEnabling) + { + if (cameraEnabled && vessel.isActiveVessel && FlightGlobals.ready) + { + //window + if (activeCam == this && TargetingCamera.ReadyForUse) + { + BDArmorySetup.WindowRectTargetingCam = GUI.Window(125452, BDArmorySetup.WindowRectTargetingCam, WindowTargetCam, "Target Camera", GUI.skin.window); + BDGUIUtils.UseMouseEventInRect(BDArmorySetup.WindowRectTargetingCam); + } + + //locked target icon + if (groundStabilized) + { + BDGUIUtils.DrawTextureOnWorldPos(groundTargetPosition, BDArmorySetup.Instance.greenPointCircleTexture, new Vector3(20, 20), 0); + } + else + { + BDGUIUtils.DrawTextureOnWorldPos(targetPointPosition, BDArmorySetup.Instance.greenCircleTexture, new Vector3(18, 18), 0); + } + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + GUI.Label(new Rect(600, 1000, 100, 100), "Slew rate: " + finalSlewSpeed); + } + + if (BDArmorySettings.DRAW_DEBUG_LINES) + { + if (groundStabilized) + { + BDGUIUtils.DrawLineBetweenWorldPositions(cameraParentTransform.position, groundTargetPosition, 2, Color.red); + } + else + { + BDGUIUtils.DrawLineBetweenWorldPositions(cameraParentTransform.position, targetPointPosition, 2, Color.red); + } + } + } + } + + void WindowTargetCam(int windowID) + { + float windowScale = BDArmorySettings.TARGET_WINDOW_SCALE; + adjCamImageSize = camImageSize * windowScale; + if (!TargetingCamera.Instance) + { + return; + } + + windowIsOpen = true; + + GUI.DragWindow(new Rect(0, 0, BDArmorySetup.WindowRectTargetingCam.width - 18, 30)); + if (GUI.Button(new Rect(BDArmorySetup.WindowRectTargetingCam.width - 18, 2, 16, 16), "X", GUI.skin.button)) + { + DisableCamera(); + return; + } + + Rect imageRect = new Rect(2, 20, adjCamImageSize, adjCamImageSize); + GUI.DrawTexture(imageRect, TargetingCamera.Instance.targetCamRenderTexture, ScaleMode.StretchToFill, false); + GUI.DrawTexture(imageRect, TargetingCamera.Instance.ReticleTexture, ScaleMode.StretchToFill, true); + + // slew buttons + DrawSlewButtons(); + + // zoom buttons + DrawZoomButtons(); + + // Right side control buttons + DrawSideControlButtons(imageRect); + + // Check for mousedown / mousescroll in target Cam and handle slew and zoom. + if (Event.current.type == EventType.MouseDown && imageRect.Contains(Event.current.mousePosition)) + { + if (!SlewingMouseCam) SlewingMouseCam = true; + } + if (Event.current.type == EventType.Repaint && SlewingMouseCam) + { + if (Mouse.delta.x != 0 && Mouse.delta.y != 0) + { + SlewRoutine(Mouse.delta); + } + } + + if (Event.current.type == EventType.Repaint && imageRect.Contains(Event.current.mousePosition)) + { + if (!wasZooming) isZooming = true; + } + + if (Event.current.type == EventType.ScrollWheel && imageRect.Contains(Event.current.mousePosition)) + { + ZoomRoutine(Input.mouseScrollDelta); + } + if (Event.current.type == EventType.Repaint && !imageRect.Contains(Event.current.mousePosition)) + { + if (wasZooming) isZooming = false; + } + + float indicatorSize = Mathf.Clamp(64 * (adjCamImageSize / camImageSize), 48, 128); + float indicatorBorder = imageRect.width * 0.056f; + Vector3 vesForward = vessel.ReferenceTransform.up; + Vector3 upDirection = (transform.position - FlightGlobals.currentMainBody.transform.position).normalized; + + //horizon indicator + float horizY = imageRect.y + imageRect.height - indicatorSize - indicatorBorder; + Vector3 hForward = Vector3.ProjectOnPlane(vesForward, upDirection); + float hAngle = -Misc.Misc.SignedAngle(hForward, vesForward, upDirection); + horizY -= (hAngle / 90) * (indicatorSize / 2); + Rect horizonRect = new Rect(indicatorBorder + imageRect.x, horizY, indicatorSize, indicatorSize); + GUI.DrawTexture(horizonRect, BDArmorySetup.Instance.horizonIndicatorTexture, ScaleMode.StretchToFill, true); + + //roll indicator + Rect rollRect = new Rect(indicatorBorder + imageRect.x, imageRect.y + imageRect.height - indicatorSize - indicatorBorder, indicatorSize, indicatorSize); + GUI.DrawTexture(rollRect, rollReferenceTexture, ScaleMode.StretchToFill, true); + Vector3 localUp = vessel.ReferenceTransform.InverseTransformDirection(upDirection); + localUp = Vector3.ProjectOnPlane(localUp, Vector3.up).normalized; + float rollAngle = -Misc.Misc.SignedAngle(-Vector3.forward, localUp, Vector3.right); + GUIUtility.RotateAroundPivot(rollAngle, rollRect.center); + GUI.DrawTexture(rollRect, rollIndicatorTexture, ScaleMode.StretchToFill, true); + GUI.matrix = Matrix4x4.identity; + + //target direction indicator + float angleToTarget = Misc.Misc.SignedAngle(hForward, Vector3.ProjectOnPlane(targetPointPosition - transform.position, upDirection), Vector3.Cross(upDirection, hForward)); + GUIUtility.RotateAroundPivot(angleToTarget, rollRect.center); + GUI.DrawTexture(rollRect, BDArmorySetup.Instance.targetDirectionTexture, ScaleMode.StretchToFill, true); + GUI.matrix = Matrix4x4.identity; + + //resizing + Rect resizeRect = + new Rect(BDArmorySetup.WindowRectTargetingCam.width - 18, BDArmorySetup.WindowRectTargetingCam.height - 18, 16, 16); + GUI.DrawTexture(resizeRect, Misc.Misc.resizeTexture, ScaleMode.StretchToFill, true); + if (Event.current.type == EventType.MouseDown && resizeRect.Contains(Event.current.mousePosition)) + { + ResizingWindow = true; + } + + if (Event.current.type == EventType.Repaint && ResizingWindow) + { + if (Mouse.delta.x != 0 || Mouse.delta.y != 0) + { + float diff = Mouse.delta.x + Mouse.delta.y; + UpdateTargetScale(diff); + ResizeTargetWindow(); + } + } + //ResetZoomKeys(); + BDGUIUtils.RepositionWindow(ref BDArmorySetup.WindowRectTargetingCam); + } + + internal static void UpdateTargetScale(float diff) + { + float scaleDiff = ((diff / (BDArmorySetup.WindowRectTargetingCam.width + BDArmorySetup.WindowRectTargetingCam.height)) * 100 * .01f); + BDArmorySettings.TARGET_WINDOW_SCALE += Mathf.Abs(scaleDiff) > .01f ? scaleDiff : scaleDiff > 0 ? .01f : -.01f; + BDArmorySettings.TARGET_WINDOW_SCALE = Mathf.Clamp(BDArmorySettings.TARGET_WINDOW_SCALE, + BDArmorySettings.TARGET_WINDOW_SCALE_MIN, + BDArmorySettings.TARGET_WINDOW_SCALE_MAX); + } + + private void DrawSlewButtons() + { + //slew buttons + float slewStartX = adjCamImageSize * 0.06f; + float slewStartY = 20 + (adjCamImageSize * 0.06f); + + Rect slewLeftRect = new Rect(slewStartX, slewStartY + ((buttonHeight + gap) / 2), buttonHeight, buttonHeight); + Rect slewUpRect = new Rect(slewStartX + buttonHeight + gap, slewStartY, buttonHeight, buttonHeight); + Rect slewDownRect = new Rect(slewStartX + buttonHeight + gap, slewStartY + buttonHeight + gap, buttonHeight, buttonHeight); + Rect slewRightRect = new Rect(slewStartX + (2 * buttonHeight) + (gap * 2), slewStartY + ((buttonHeight + gap) / 2), buttonHeight, buttonHeight); + if (GUI.RepeatButton(slewUpRect, "^", GUI.skin.button)) + { + //SlewCamera(Vector3.up); + slewInput.y = 1; + } + + if (GUI.RepeatButton(slewDownRect, "v", GUI.skin.button)) + { + //SlewCamera(Vector3.down); + slewInput.y = -1; + } + + if (GUI.RepeatButton(slewLeftRect, "<", GUI.skin.button)) + { + //SlewCamera(Vector3.left); + slewInput.x = -1; + } + + if (GUI.RepeatButton(slewRightRect, ">", GUI.skin.button)) + { + //SlewCamera(Vector3.right); + slewInput.x = 1; + } + } + + private void DrawZoomButtons() + { + float zoomStartX = adjCamImageSize * 0.94f - (buttonHeight * 3) - (4 * gap); + float zoomStartY = 20 + (adjCamImageSize * 0.06f); + Rect zoomOutRect = new Rect(zoomStartX, zoomStartY, buttonHeight, buttonHeight); + Rect zoomInfoRect = new Rect(zoomStartX + buttonHeight + gap, zoomStartY, buttonHeight + 4 * gap, buttonHeight); + Rect zoomInRect = new Rect(zoomStartX + buttonHeight * 2 + 5 * gap, zoomStartY, buttonHeight, buttonHeight); + + GUI.enabled = currentFovIndex > 0; + if (GUI.Button(zoomOutRect, "-", GUI.skin.button)) + { + ZoomOut(); + } + + GUIStyle zoomBox = GUI.skin.box; + zoomBox.alignment = TextAnchor.UpperCenter; + zoomBox.padding.top = 0; + GUI.enabled = true; + GUI.Label(zoomInfoRect, (currentFovIndex + 1).ToString() + "X", zoomBox); + + GUI.enabled = currentFovIndex < zoomFovs.Length - 1; + if (GUI.Button(zoomInRect, "+", GUI.skin.button)) + { + ZoomIn(); + } + GUI.enabled = true; + } + + private void DrawSideControlButtons(Rect imageRect) + { + GUIStyle dataStyle = new GUIStyle + { + alignment = TextAnchor.MiddleCenter, + normal = + { + textColor = Color.white + } + }; + GUIStyle buttonStyle = new GUIStyle(BDArmorySetup.BDGuiSkin.button) + { + fontSize = 11 + }; + + float line = buttonHeight + gap; + float buttonWidth = 3 * buttonHeight + 4 * gap; + //groundStablize button + float startX = imageRect.width + 3 * gap; + Rect stabilizeRect = new Rect(startX, controlsStartY, buttonWidth, buttonHeight + line); + if (!groundStabilized) + { + if (GUI.Button(stabilizeRect, "Lock\nTarget", buttonStyle)) + { + GroundStabilize(); + } + } + else + { + if (GUI.Button(new Rect(startX, controlsStartY, buttonWidth, buttonHeight), + "Unlock", buttonStyle)) + { + ClearTarget(); + } + + if (weaponManager) + { + Rect sendGPSRect = new Rect(startX, controlsStartY + line, buttonWidth, buttonHeight); + if (GUI.Button(sendGPSRect, "Send GPS", buttonStyle)) + { + SendGPS(); + } + } + + if (!gimbalLimitReached) + { + //open square + float oSqrSize = (24f / 512f) * adjCamImageSize; + Rect oSqrRect = new Rect(imageRect.x + (adjCamImageSize / 2) - (oSqrSize / 2), + imageRect.y + (adjCamImageSize / 2) - (oSqrSize / 2), oSqrSize, oSqrSize); + GUI.DrawTexture(oSqrRect, BDArmorySetup.Instance.openWhiteSquareTexture, ScaleMode.StretchToFill, true); + } + + //geo data + dataStyle.fontSize = (int)Mathf.Clamp(12 * BDArmorySettings.TARGET_WINDOW_SCALE, 8, 12); + Rect geoRect = new Rect(imageRect.x, (adjCamImageSize * 0.94f), adjCamImageSize, 14); + string geoLabel = Misc.Misc.FormattedGeoPos(bodyRelativeGTP, false); + GUI.Label(geoRect, geoLabel, dataStyle); + + //target data + dataStyle.fontSize = (int)Mathf.Clamp(16 * BDArmorySettings.TARGET_WINDOW_SCALE, 9, 16); + //float dataStartX = stabilStartX + stabilizeRect.width + 8; + Rect targetRangeRect = new Rect(imageRect.x, (adjCamImageSize * 0.94f) - (int)Mathf.Clamp(18 * BDArmorySettings.TARGET_WINDOW_SCALE, 9, 18), adjCamImageSize, (int)Mathf.Clamp(18 * BDArmorySettings.TARGET_WINDOW_SCALE, 10, 18)); + float targetRange = Vector3.Distance(groundTargetPosition, transform.position); + string rangeString = "Range: " + targetRange.ToString("0.0") + "m"; + GUI.Label(targetRangeRect, rangeString, dataStyle); + + //laser ranging indicator + dataStyle.fontSize = (int)Mathf.Clamp(18 * BDArmorySettings.TARGET_WINDOW_SCALE, 9, 18); + string lrLabel = surfaceDetected ? "LR" : "NO LR"; + Rect lrRect = new Rect(imageRect.x, imageRect.y + (adjCamImageSize * 0.65f), adjCamImageSize, 20); + GUI.Label(lrRect, lrLabel, dataStyle); + + //azimuth and elevation indicator //UNFINISHED + /* + Vector2 azielPos = TargetAzimuthElevationScreenPos(imageRect, groundTargetPosition, 4); + Rect azielRect = new Rect(azielPos.x, azielPos.y, 4, 4); + GUI.DrawTexture(azielRect, BDArmorySetup.Instance.whiteSquareTexture, ScaleMode.StretchToFill, true); + */ + + //DLZ + if (weaponManager && weaponManager.selectedWeapon != null) + { + if (weaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) + { + MissileBase currMissile = weaponManager.CurrentMissile; + if (currMissile.TargetingMode == MissileBase.TargetingModes.Gps || + currMissile.TargetingMode == MissileBase.TargetingModes.Laser) + { + MissileLaunchParams dlz = + MissileLaunchParams.GetDynamicLaunchParams(currMissile, Vector3.zero, groundTargetPosition); + float dlzWidth = 12 * (imageRect.width / 360); + float lineWidth = 2; + Rect dlzRect = new Rect(imageRect.x + imageRect.width - (3 * dlzWidth) - lineWidth, + imageRect.y + (imageRect.height / 4), dlzWidth, imageRect.height / 2); + float scaleDistance = + Mathf.Max(Mathf.Max(8000f, currMissile.maxStaticLaunchRange * 2), targetRange); + float rangeToPixels = (1f / scaleDistance) * dlzRect.height; + + GUI.BeginGroup(dlzRect); + + float dlzX = 0; + + BDGUIUtils.DrawRectangle(new Rect(0, 0, dlzWidth, dlzRect.height), Color.black); + + Rect maxRangeVertLineRect = new Rect(dlzRect.width - lineWidth, + Mathf.Clamp(dlzRect.height - (dlz.maxLaunchRange * rangeToPixels), 0, dlzRect.height), + lineWidth, Mathf.Clamp(dlz.maxLaunchRange * rangeToPixels, 0, dlzRect.height)); + BDGUIUtils.DrawRectangle(maxRangeVertLineRect, Color.white); + + Rect maxRangeTickRect = new Rect(dlzX, maxRangeVertLineRect.y, dlzWidth, lineWidth); + BDGUIUtils.DrawRectangle(maxRangeTickRect, Color.white); + + Rect minRangeTickRect = new Rect(dlzX, + Mathf.Clamp(dlzRect.height - (dlz.minLaunchRange * rangeToPixels), 0, dlzRect.height), dlzWidth, + lineWidth); + BDGUIUtils.DrawRectangle(minRangeTickRect, Color.white); + + Rect rTrTickRect = new Rect(dlzX, + Mathf.Clamp(dlzRect.height - (dlz.rangeTr * rangeToPixels), 0, dlzRect.height), dlzWidth, + lineWidth); + BDGUIUtils.DrawRectangle(rTrTickRect, Color.white); + + Rect noEscapeLineRect = + new Rect(dlzX, rTrTickRect.y, lineWidth, minRangeTickRect.y - rTrTickRect.y); + BDGUIUtils.DrawRectangle(noEscapeLineRect, Color.white); + + GUI.EndGroup(); + + float targetDistIconSize = 6; + float targetDistY = dlzRect.y + dlzRect.height - (targetRange * rangeToPixels); + Rect targetDistanceRect = new Rect(dlzRect.x - (targetDistIconSize / 2), targetDistY, + (targetDistIconSize / 2) + dlzRect.width, targetDistIconSize); + BDGUIUtils.DrawRectangle(targetDistanceRect, Color.white); + } + } + } + } + + //gimbal limit + dataStyle.fontSize = (int)Mathf.Clamp(24 * BDArmorySettings.TARGET_WINDOW_SCALE, 12, 24); + if (gimbalLimitReached) + { + Rect gLimRect = new Rect(imageRect.x, imageRect.y + (adjCamImageSize * 0.15f), adjCamImageSize, 28); + GUI.Label(gLimRect, "GIMBAL LIMIT", dataStyle); + } + + //reset button + Rect resetRect = new Rect(startX, controlsStartY + (2 * line), buttonWidth, buttonHeight); + if (GUI.Button(resetRect, "Reset", buttonStyle)) + { + ResetCameraButton(); + } + + //CoM lock + Rect comLockRect = new Rect(startX, controlsStartY + 3 * line, buttonWidth, buttonHeight); + GUIStyle comStyle = new GUIStyle(CoMLock ? BDArmorySetup.BDGuiSkin.box : buttonStyle); + comStyle.fontSize = 10; + comStyle.wordWrap = false; + if (GUI.Button(comLockRect, "CoM Track", comStyle)) + { + CoMLock = !CoMLock; + } + + //radar slave + Rect radarSlaveRect = new Rect(startX, controlsStartY + 4 * line, buttonWidth, buttonHeight); + GUIStyle radarSlaveStyle = radarLock ? BDArmorySetup.BDGuiSkin.box : buttonStyle; + if (GUI.Button(radarSlaveRect, "Radar", radarSlaveStyle)) + { + radarLock = !radarLock; + } + + //slave turrets button + Rect slaveRect = new Rect(startX, controlsStartY + 5 * line, buttonWidth, buttonHeight); + if (!slaveTurrets) + { + if (GUI.Button(slaveRect, "Turrets", buttonStyle)) + { + SlaveTurrets(); + } + } + else + { + if (GUI.Button(slaveRect, "Turrets", BDArmorySetup.BDGuiSkin.box)) + { + UnslaveTurrets(); + } + } + + //point to gps button + Rect toGpsRect = new Rect(startX, controlsStartY + 6 * line, buttonWidth, buttonHeight); + if (GUI.Button(toGpsRect, "To GPS", buttonStyle)) + { + PointToGPSTarget(); + } + + //nv button + float nvStartX = startX; + Rect nvRect = new Rect(nvStartX, controlsStartY + 7 * line, buttonWidth, buttonHeight); + string nvLabel = nvMode ? "NV Off" : "NV On"; + GUIStyle nvStyle = nvMode ? BDArmorySetup.BDGuiSkin.box : buttonStyle; + if (GUI.Button(nvRect, nvLabel, nvStyle)) + { + ToggleNV(); + } + } + + void ResetCameraButton() + { + if (!resetting) + { + StartCoroutine("ResetCamera"); + } + } + + void SendGPS() + { + if (groundStabilized && weaponManager) + { + BDATargetManager.GPSTargetList(weaponManager.Team).Add(new GPSTargetInfo(bodyRelativeGTP, "Target")); + BDATargetManager.Instance.SaveGPSTargets(); + } + } + + void SlaveTurrets() + { + List.Enumerator mtc = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + mtc.Current.slaveTurrets = false; + } + mtc.Dispose(); + + if (weaponManager && weaponManager.vesselRadarData) + { + weaponManager.vesselRadarData.slaveTurrets = false; + } + + slaveTurrets = true; + } + + void UnslaveTurrets() + { + List.Enumerator mtc = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + mtc.Current.slaveTurrets = false; + } + mtc.Dispose(); + + if (weaponManager && weaponManager.vesselRadarData) + { + weaponManager.vesselRadarData.slaveTurrets = false; + } + + if (weaponManager) + { + weaponManager.slavingTurrets = false; + } + } + + void UpdateSlaveData() + { + if (!slaveTurrets) return; + if (!weaponManager) return; + weaponManager.slavingTurrets = true; + weaponManager.slavedPosition = groundStabilized ? groundTargetPosition : targetPointPosition; + weaponManager.slavedVelocity = Vector3.zero; + weaponManager.slavedAcceleration = Vector3.zero; + } + + internal static void ResizeTargetWindow() + { + windowWidth = camImageSize * BDArmorySettings.TARGET_WINDOW_SCALE + (3 * buttonHeight) + 16 + 2 * gap; + windowHeight = camImageSize * BDArmorySettings.TARGET_WINDOW_SCALE + 23; + BDArmorySetup.WindowRectTargetingCam = new Rect(BDArmorySetup.WindowRectTargetingCam.x, BDArmorySetup.WindowRectTargetingCam.y, windowWidth, windowHeight); + } + + void SlewCamera(Vector3 direction) + { + SlewingButtonCam = true; + StartCoroutine(SlewCamRoutine(direction)); + } + + IEnumerator SlewMouseCamRoutine(Vector3 direction) + { + radarLock = false; + //invert the x axis. makes the mouse action more intutitve + direction.x = -direction.x; + //direction.y = -direction.y; + float velocity = Mathf.Abs(direction.x) > Mathf.Abs(direction.y) ? Mathf.Abs(direction.x) : Mathf.Abs(direction.y); + Vector3 rotationAxis = Matrix4x4.TRS(Vector3.zero, Quaternion.LookRotation(cameraParentTransform.forward, vessel.upAxis), Vector3.one) + .MultiplyVector(Quaternion.AngleAxis(90, Vector3.forward) * direction); + float angle = velocity / (1 + currentFovIndex) * Time.deltaTime; + if (angle / (1f + currentFovIndex) < .05f / (1f + currentFovIndex)) angle = .05f / ((1f + currentFovIndex) / 2f); + Vector3 lookVector = Quaternion.AngleAxis(angle, rotationAxis) * cameraParentTransform.forward; + + PointCameraModel(lookVector); + yield return new WaitForEndOfFrame(); + + if (groundStabilized) + { + GroundStabilize(); + lookVector = groundTargetPosition - cameraParentTransform.position; + } + PointCameraModel(lookVector); + } + + IEnumerator SlewCamRoutine(Vector3 direction) + { + StopResetting(); + StopPointToPosRoutine(); + + radarLock = false; + float slewRate = finalSlewSpeed; + Vector3 rotationAxis = Matrix4x4.TRS(Vector3.zero, Quaternion.LookRotation(cameraParentTransform.forward, vessel.upAxis), Vector3.one).MultiplyVector(Quaternion.AngleAxis(90, Vector3.forward) * direction); + Vector3 lookVector = Quaternion.AngleAxis(slewRate * Time.deltaTime, rotationAxis) * cameraParentTransform.forward; + PointCameraModel(lookVector); + yield return new WaitForEndOfFrame(); + + if (groundStabilized) + { + GroundStabilize(); + lookVector = groundTargetPosition - cameraParentTransform.position; + } + + PointCameraModel(lookVector); + } + + void PointToGPSTarget() + { + if (weaponManager && weaponManager.designatedGPSCoords != Vector3d.zero) + { + StartCoroutine(PointToPositionRoutine(VectorUtils.GetWorldSurfacePostion(weaponManager.designatedGPSCoords, vessel.mainBody))); + } + } + + private void ResetZoomKeys() + { + ZoomKeysSet = false; + GameSettings.AXIS_MOUSEWHEEL.primary = ZoomKeyP; + GameSettings.AXIS_MOUSEWHEEL.secondary = ZoomKeyS; + } + + private void SetZoomKeys() + { + ZoomKeysSet = true; + GameSettings.AXIS_MOUSEWHEEL.primary = NoZoomKeyP; + GameSettings.AXIS_MOUSEWHEEL.secondary = NoZoomKeyS; + } + + private void SlewRoutine(Vector2 direction) + { + if (SlewingMouseCam) + { + StartCoroutine(SlewMouseCamRoutine(direction)); + } + } + + void ZoomRoutine(Vector2 zoomAmt) + { + if (zoomAmt.y > 0) ZoomIn(); + else ZoomOut(); + Mouse.delta = new Vector2(0, 0); + } + + void ZoomIn() + { + StopResetting(); + if (currentFovIndex < zoomFovs.Length - 1) + { + currentFovIndex++; + } + + //fov = zoomFovs[currentFovIndex]; + } + + void ZoomOut() + { + StopResetting(); + if (currentFovIndex > 0) + { + currentFovIndex--; + } + + //fov = zoomFovs[currentFovIndex]; + } + + GameObject debugSphere; + + void CreateDebugSphere() + { + debugSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + debugSphere.GetComponent().enabled = false; + } + + void MoveDebugSphere() + { + if (!debugSphere) + { + CreateDebugSphere(); + } + debugSphere.transform.position = groundTargetPosition; + } + + void GroundStabilize() + { + if (vessel.packed) return; + StopResetting(); + + RaycastHit rayHit; + Ray ray = new Ray(cameraParentTransform.position + (50 * cameraParentTransform.forward), cameraParentTransform.forward); + bool raycasted = Physics.Raycast(ray, out rayHit, maxRayDistance - 50, 9076737); + if (raycasted) + { + if (FlightGlobals.getAltitudeAtPos(rayHit.point) < 0) + { + raycasted = false; + } + else + { + groundStabilized = true; + groundTargetPosition = rayHit.point; + + if (CoMLock) + { + KerbalEVA hitEVA = rayHit.collider.gameObject.GetComponentUpwards(); + Part p = hitEVA ? hitEVA.part : rayHit.collider.GetComponentInParent(); + if (p && p.vessel && p.vessel.CoM != Vector3.zero) + { + groundTargetPosition = p.vessel.CoM + (p.vessel.Velocity() * Time.fixedDeltaTime); + StartCoroutine(StabilizeNextFrame()); + } + } + Vector3d newGTP = VectorUtils.WorldPositionToGeoCoords(groundTargetPosition, vessel.mainBody); + if (newGTP != Vector3d.zero) + { + bodyRelativeGTP = newGTP; + } + } + } + + if (!raycasted) + { + Vector3 upDir = VectorUtils.GetUpDirection(cameraParentTransform.position); + double altitude = vessel.altitude; //MissileGuidance.GetRadarAltitude(vessel); + double radius = vessel.mainBody.Radius; + + Vector3d planetCenter = vessel.GetWorldPos3D() - ((vessel.altitude + vessel.mainBody.Radius) * vessel.upAxis); + double enter; + if (VectorUtils.SphereRayIntersect(ray, planetCenter, radius, out enter)) + { + if (enter > 0) + { + groundStabilized = true; + groundTargetPosition = ray.GetPoint((float)enter); + Vector3d newGTP = VectorUtils.WorldPositionToGeoCoords(groundTargetPosition, vessel.mainBody); + if (newGTP != Vector3d.zero) + { + bodyRelativeGTP = newGTP; + } + } + } + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + MoveDebugSphere(); + } + } + + IEnumerator StabilizeNextFrame() + { + yield return new WaitForFixedUpdate(); + yield return new WaitForEndOfFrame(); + if (!gimbalLimitReached && surfaceDetected) + { + GroundStabilize(); + } + } + + void GetHitPoint() + { + if (vessel.packed) return; + if (delayedEnabling) return; + + RaycastHit rayHit; + Ray ray = new Ray(cameraParentTransform.position + (50 * cameraParentTransform.forward), cameraParentTransform.forward); + if (Physics.Raycast(ray, out rayHit, maxRayDistance - 50, 9076737)) + { + targetPointPosition = rayHit.point; + + if (!surfaceDetected && groundStabilized && !gimbalLimitReached) + { + groundStabilized = true; + groundTargetPosition = rayHit.point; + + if (CoMLock) + { + KerbalEVA hitEVA = rayHit.collider.gameObject.GetComponentUpwards(); + Part p = hitEVA ? hitEVA.part : rayHit.collider.GetComponentInParent(); + if (p && p.vessel && p.vessel.Landed) + { + groundTargetPosition = p.vessel.CoM; + } + } + Vector3d newGTP = VectorUtils.WorldPositionToGeoCoords(groundTargetPosition, vessel.mainBody); + if (newGTP != Vector3d.zero) + { + bodyRelativeGTP = newGTP; + } + } + + surfaceDetected = true; + + if (groundStabilized && !gimbalLimitReached && CMDropper.smokePool != null) + { + if (CMSmoke.RaycastSmoke(ray)) + { + surfaceDetected = false; + } + } + } + else + { + targetPointPosition = cameraParentTransform.position + (maxRayDistance * cameraParentTransform.forward); + surfaceDetected = false; + } + } + + void ClearTarget() + { + groundStabilized = false; + } + + IEnumerator ResetCamera() + { + resetting = true; + radarLock = false; + StopPointToPosRoutine(); + + if (groundStabilized) + { + ClearTarget(); + } + + currentFovIndex = 0; + //fov = zoomFovs[currentFovIndex]; + + while (Vector3.Angle(cameraParentTransform.forward, cameraParentTransform.parent.forward) > 0.1f) + { + Vector3 newForward = Vector3.RotateTowards(cameraParentTransform.forward, cameraParentTransform.parent.forward, 60 * Mathf.Deg2Rad * Time.deltaTime, 0); + //cameraParentTransform.rotation = Quaternion.LookRotation(newForward, VectorUtils.GetUpDirection(transform.position)); + PointCameraModel(newForward); + gimbalLimitReached = false; + yield return null; + } + resetting = false; + } + + void StopPointToPosRoutine() + { + if (slewingToPosition) + { + StartCoroutine(StopPTPRRoutine()); + } + } + + IEnumerator StopPTPRRoutine() + { + stopPTPR = true; + yield return null; + yield return new WaitForEndOfFrame(); + stopPTPR = false; + } + + bool stopPTPR; + bool slewingToPosition; + + public IEnumerator PointToPositionRoutine(Vector3 position) + { + yield return StopPTPRRoutine(); + stopPTPR = false; + slewingToPosition = true; + radarLock = false; + StopResetting(); + ClearTarget(); + while (!stopPTPR && Vector3.Angle(cameraParentTransform.transform.forward, position - (cameraParentTransform.transform.position)) > 0.1f) + { + Vector3 newForward = Vector3.RotateTowards(cameraParentTransform.transform.forward, position - cameraParentTransform.transform.position, 90 * Mathf.Deg2Rad * Time.fixedDeltaTime, 0); + //cameraParentTransform.rotation = Quaternion.LookRotation(newForward, VectorUtils.GetUpDirection(transform.position)); + PointCameraModel(newForward); + yield return new WaitForFixedUpdate(); + if (gimbalLimitReached) + { + ClearTarget(); + StartCoroutine("ResetCamera"); + slewingToPosition = false; + yield break; + } + } + if (surfaceDetected && !stopPTPR) + { + //cameraParentTransform.transform.rotation = Quaternion.LookRotation(position - cameraParentTransform.position, VectorUtils.GetUpDirection(transform.position)); + PointCameraModel(position - cameraParentTransform.position); + GroundStabilize(); + } + slewingToPosition = false; + yield break; + } + + void StopResetting() + { + if (resetting) + { + StopCoroutine("ResetCamera"); + resetting = false; + } + } + + void ParseFovs() + { + zoomFovs = Misc.Misc.ParseToFloatArray(zoomFOVs); + } + + void OnDestroy() + { + if (HighLogic.LoadedSceneIsFlight) + { + windowIsOpen = false; + if (wpmr) + { + if (slaveTurrets) + { + weaponManager.slavingTurrets = false; + } + } + + GameEvents.onVesselCreate.Remove(Disconnect); + } + } + + Vector2 TargetAzimuthElevationScreenPos(Rect screenRect, Vector3 targetPosition, float textureSize) + { + Vector3 localPos = vessel.ReferenceTransform.InverseTransformPoint(targetPosition); + Vector3 aziRef = Vector3.up; + Vector3 aziPos = Vector3.ProjectOnPlane(localPos, Vector3.forward); + float elevation = VectorUtils.SignedAngle(aziPos, localPos, Vector3.forward); + float normElevation = elevation / 70; + + float azimuth = VectorUtils.SignedAngle(aziRef, aziPos, Vector3.right); + float normAzimuth = Mathf.Clamp(azimuth / 120, -1, 1); + + float x = screenRect.x + (screenRect.width / 2) + (normAzimuth * (screenRect.width / 2)) - (textureSize / 2); + float y = screenRect.y + (screenRect.height / 4) + (normElevation * (screenRect.height / 4)) - (textureSize / 2); + + x = Mathf.Clamp(x, textureSize / 2, screenRect.width - (textureSize / 2)); + y = Mathf.Clamp(y, textureSize / 2, (screenRect.height) - (textureSize / 2)); + + return new Vector2(x, y); + } + } +} diff --git a/BDArmory/Modules/ModuleTurret.cs b/BDArmory/Modules/ModuleTurret.cs new file mode 100644 index 000000000..4c115a29c --- /dev/null +++ b/BDArmory/Modules/ModuleTurret.cs @@ -0,0 +1,349 @@ +using System; +using BDArmory.Core; +using BDArmory.Misc; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class ModuleTurret : PartModule + { + [KSPField] public int turretID = 0; + + [KSPField] public string pitchTransformName = "pitchTransform"; + public Transform pitchTransform; + + [KSPField] public string yawTransformName = "yawTransform"; + public Transform yawTransform; + + Transform referenceTransform; //set this to gun's fireTransform + + [KSPField] public float pitchSpeedDPS; + [KSPField] public float yawSpeedDPS; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxPitch"),//Max Pitch + UI_FloatRange(minValue = 0f, maxValue = 60f, stepIncrement = 1f, scene = UI_Scene.All)] + public float maxPitch; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_MinPitch"),//Min Pitch + UI_FloatRange(minValue = 1f, maxValue = 0f, stepIncrement = 1f, scene = UI_Scene.All)] + public float minPitch; + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_YawRange"),//Yaw Range + UI_FloatRange(minValue = 1f, maxValue = 60f, stepIncrement = 1f, scene = UI_Scene.All)] + public float yawRange; + + [KSPField(isPersistant = true)] public float minPitchLimit = 400; + [KSPField(isPersistant = true)] public float maxPitchLimit = 400; + [KSPField(isPersistant = true)] public float yawRangeLimit = 400; + + [KSPField] public bool smoothRotation = false; + [KSPField] public float smoothMultiplier = 10; + + //sfx + [KSPField] public string audioPath; + [KSPField] public float maxAudioPitch = 0.5f; + [KSPField] public float minAudioPitch = 0f; + [KSPField] public float maxVolume = 1; + [KSPField] public float minVolume = 0; + + AudioClip soundClip; + AudioSource audioSource; + bool hasAudio; + float audioRotationRate; + float targetAudioRotationRate; + Vector3 lastTurretDirection; + float maxAudioRotRate; + + public override void OnStart(StartState state) + { + base.OnStart(state); + + SetupTweakables(); + + pitchTransform = part.FindModelTransform(pitchTransformName); + yawTransform = part.FindModelTransform(yawTransformName); + + if (!pitchTransform) + { + Debug.LogWarning(part.partInfo.title + " has no pitchTransform"); + } + + if (!yawTransform) + { + Debug.LogWarning(part.partInfo.title + " has no yawTransform"); + } + + if (!referenceTransform) + { + SetReferenceTransform(pitchTransform); + } + + if (!string.IsNullOrEmpty(audioPath) && (yawSpeedDPS != 0 || pitchSpeedDPS != 0)) + { + soundClip = GameDatabase.Instance.GetAudioClip(audioPath); + + audioSource = gameObject.AddComponent(); + audioSource.clip = soundClip; + audioSource.loop = true; + audioSource.dopplerLevel = 0; + audioSource.minDistance = .5f; + audioSource.maxDistance = 150; + audioSource.Play(); + audioSource.volume = 0; + audioSource.pitch = 0; + audioSource.priority = 9999; + audioSource.spatialBlend = 1; + + lastTurretDirection = yawTransform.parent.InverseTransformDirection(pitchTransform.forward); + + maxAudioRotRate = Mathf.Min(yawSpeedDPS, pitchSpeedDPS); + + hasAudio = true; + } + } + + void FixedUpdate() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (hasAudio) + { + audioRotationRate = Mathf.Lerp(audioRotationRate, targetAudioRotationRate, 20 * Time.fixedDeltaTime); + audioRotationRate = Mathf.Clamp01(audioRotationRate); + + if (audioRotationRate < 0.05f) + { + audioSource.volume = 0; + } + else + { + audioSource.volume = Mathf.Clamp(2f * audioRotationRate, + minVolume * BDArmorySettings.BDARMORY_WEAPONS_VOLUME, + maxVolume * BDArmorySettings.BDARMORY_WEAPONS_VOLUME); + audioSource.pitch = Mathf.Clamp(audioRotationRate, minAudioPitch, maxAudioPitch); + } + + Vector3 tDir = yawTransform.parent.InverseTransformDirection(pitchTransform.forward); + float angle = Vector3.Angle(tDir, lastTurretDirection); + float rate = Mathf.Clamp01((angle / Time.fixedDeltaTime) / maxAudioRotRate); + lastTurretDirection = tDir; + + targetAudioRotationRate = rate; + } + } + } + + void Update() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (hasAudio) + { + if (!BDArmorySetup.GameIsPaused && audioRotationRate > 0.05f) + { + if (!audioSource.isPlaying) audioSource.Play(); + } + else + { + if (audioSource.isPlaying) + { + audioSource.Stop(); + } + } + } + } + } + + public void AimToTarget(Vector3 targetPosition, bool pitch = true, bool yaw = true) + { + AimInDirection(targetPosition - referenceTransform.position, pitch, yaw); + } + + public void AimInDirection(Vector3 targetDirection, bool pitch = true, bool yaw = true) + { + if (!yawTransform) + { + return; + } + + float deltaTime = Time.fixedDeltaTime; + + Vector3 yawNormal = yawTransform.up; + Vector3 yawComponent = Vector3.ProjectOnPlane(targetDirection, yawNormal); + Vector3 pitchNormal = Vector3.Cross(yawComponent, yawNormal); + Vector3 pitchComponent = Vector3.ProjectOnPlane(targetDirection, pitchNormal); + + float currentYaw = yawTransform.localEulerAngles.y.ToAngle(); + float yawError = VectorUtils.SignedAngleDP( + Vector3.ProjectOnPlane(referenceTransform.forward, yawNormal), + yawComponent, + Vector3.Cross(yawNormal, referenceTransform.forward)); + float yawOffset = Mathf.Abs(yawError); + float targetYawAngle = (currentYaw + yawError).ToAngle(); + // clamp target yaw in a non-wobbly way + if (Mathf.Abs(targetYawAngle) > yawRange / 2) + { + var nonWooblyWay = Vector3.Dot(yawTransform.parent.right, + targetDirection + referenceTransform.position - yawTransform.position); + if (float.IsNaN(nonWooblyWay)) return; + + targetYawAngle = yawRange / 2 * Math.Sign(nonWooblyWay); + } + + + float pitchError = (float)Vector3d.Angle(pitchComponent, yawNormal) - (float)Vector3d.Angle(referenceTransform.forward, yawNormal); + float currentPitch = -pitchTransform.localEulerAngles.x.ToAngle(); // from current rotation transform + float targetPitchAngle = currentPitch - pitchError; + float pitchOffset = Mathf.Abs(targetPitchAngle - currentPitch); + targetPitchAngle = Mathf.Clamp(targetPitchAngle, minPitch, maxPitch); // clamp pitch + + float linPitchMult = yawOffset > 0 ? Mathf.Clamp01((pitchOffset / yawOffset) * (yawSpeedDPS / pitchSpeedDPS)) : 1; + float linYawMult = pitchOffset > 0 ? Mathf.Clamp01((yawOffset / pitchOffset) * (pitchSpeedDPS / yawSpeedDPS)) : 1; + + float yawSpeed; + float pitchSpeed; + if (smoothRotation) + { + yawSpeed = Mathf.Clamp(yawOffset * smoothMultiplier, 1f, yawSpeedDPS) * deltaTime; + pitchSpeed = Mathf.Clamp(pitchOffset * smoothMultiplier, 1f, pitchSpeedDPS) * deltaTime; + } + else + { + yawSpeed = yawSpeedDPS * deltaTime; + pitchSpeed = pitchSpeedDPS * deltaTime; + } + + yawSpeed *= linYawMult; + pitchSpeed *= linPitchMult; + + if (yawRange < 360 && Mathf.Abs(currentYaw - targetYawAngle) >= 180) + { + if (float.IsNaN(currentYaw)) + { + return; + } + + targetYawAngle = currentYaw - (Math.Sign(currentYaw) * 179); + } + + if (yaw) + yawTransform.localRotation = Quaternion.RotateTowards(yawTransform.localRotation, + Quaternion.Euler(0, targetYawAngle, 0), yawSpeed); + if (pitch) + pitchTransform.localRotation = Quaternion.RotateTowards(pitchTransform.localRotation, + Quaternion.Euler(-targetPitchAngle, 0, 0), pitchSpeed); + } + + public bool ReturnTurret() + { + if (!yawTransform) + { + return false; + } + + float deltaTime = Time.fixedDeltaTime; + + float yawOffset = Vector3.Angle(yawTransform.forward, yawTransform.parent.forward); + float pitchOffset = Vector3.Angle(pitchTransform.forward, yawTransform.forward); + + float yawSpeed; + float pitchSpeed; + + if (smoothRotation) + { + yawSpeed = Mathf.Clamp(yawOffset * smoothMultiplier, 1f, yawSpeedDPS) * deltaTime; + pitchSpeed = Mathf.Clamp(pitchOffset * smoothMultiplier, 1f, pitchSpeedDPS) * deltaTime; + } + else + { + yawSpeed = yawSpeedDPS * deltaTime; + pitchSpeed = pitchSpeedDPS * deltaTime; + } + + float linPitchMult = yawOffset > 0 ? Mathf.Clamp01((pitchOffset / yawOffset) * (yawSpeedDPS / pitchSpeedDPS)) : 1; + float linYawMult = pitchOffset > 0 ? Mathf.Clamp01((yawOffset / pitchOffset) * (pitchSpeedDPS / yawSpeedDPS)) : 1; + + yawSpeed *= linYawMult; + pitchSpeed *= linPitchMult; + + yawTransform.localRotation = Quaternion.RotateTowards(yawTransform.localRotation, Quaternion.identity, + yawSpeed); + pitchTransform.localRotation = Quaternion.RotateTowards(pitchTransform.localRotation, Quaternion.identity, + pitchSpeed); + + if (yawTransform.localRotation == Quaternion.identity && pitchTransform.localRotation == Quaternion.identity) + { + return true; + } + return false; + } + + public bool TargetInRange(Vector3 targetPosition, float thresholdDegrees, float maxDistance) + { + if (!pitchTransform) + { + return false; + } + bool withinView = Vector3.Angle(targetPosition - pitchTransform.position, pitchTransform.forward) < + thresholdDegrees; + bool withinDistance = (targetPosition - pitchTransform.position).sqrMagnitude < maxDistance * maxDistance; + return (withinView && withinDistance); + } + + public void SetReferenceTransform(Transform t) + { + referenceTransform = t; + } + + void SetupTweakables() + { + UI_FloatRange minPitchRange = (UI_FloatRange)Fields["minPitch"].uiControlEditor; + if (minPitchLimit > 90) + { + minPitchLimit = minPitch; + } + if (minPitchLimit == 0) + { + Fields["minPitch"].guiActiveEditor = false; + } + minPitchRange.minValue = minPitchLimit; + minPitchRange.maxValue = 0; + + UI_FloatRange maxPitchRange = (UI_FloatRange)Fields["maxPitch"].uiControlEditor; + if (maxPitchLimit > 90) + { + maxPitchLimit = maxPitch; + } + if (maxPitchLimit == 0) + { + Fields["maxPitch"].guiActiveEditor = false; + } + maxPitchRange.maxValue = maxPitchLimit; + maxPitchRange.minValue = 0; + + UI_FloatRange yawRangeEd = (UI_FloatRange)Fields["yawRange"].uiControlEditor; + if (yawRangeLimit > 360) + { + yawRangeLimit = yawRange; + } + + if (yawRangeLimit == 0) + { + Fields["yawRange"].guiActiveEditor = false; + } + else if (yawRangeLimit < 0) + { + yawRangeEd.minValue = 0; + yawRangeEd.maxValue = 360; + + if (yawRange < 0) yawRange = 360; + } + else + { + yawRangeEd.minValue = 0; + yawRangeEd.maxValue = yawRangeLimit; + } + } + } +} diff --git a/BDArmory/Modules/ModuleWWC.cs b/BDArmory/Modules/ModuleWWC.cs new file mode 100644 index 000000000..a1eb46a4b --- /dev/null +++ b/BDArmory/Modules/ModuleWWC.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; + +namespace BDArmory.Modules +{ + public class ModuleWWC : PartModule + { + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_DeactivationDepth"),//Deactivation Depth + UI_FloatRange(controlEnabled = true, scene = UI_Scene.All, minValue = 0f, maxValue = -200f, stepIncrement = 1f)] + public float CutOffDepth = -5; + + public void Update() + { + if (HighLogic.LoadedSceneIsFlight && vessel.altitude < CutOffDepth) + { + DisableWeapons(); + } + } + + private void DisableWeapons() + { + List turrets = new List(200); + foreach (Part p in vessel.Parts) + { + turrets.AddRange(p.FindModulesImplementing()); + } + foreach (ModuleTurret turret in turrets) + { + turret.maxPitch = 0; + turret.yawRange = 0; + turret.pitchSpeedDPS = 0; + } + + List weapons = new List(200); + foreach (Part p in vessel.Parts) + { + weapons.AddRange(p.FindModulesImplementing()); + } + foreach (ModuleWeapon weapon in weapons) + { + weapon.engageGround = false; + weapon.engageAir = false; + weapon.engageMissile = false; + weapon.engageSLW = false; + weapon.engageRangeMin = 0; + } + } + } +} diff --git a/BDArmory/Modules/ModuleWeapon.cs b/BDArmory/Modules/ModuleWeapon.cs new file mode 100644 index 000000000..f234a8ef4 --- /dev/null +++ b/BDArmory/Modules/ModuleWeapon.cs @@ -0,0 +1,2561 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using BDArmory.Bullets; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Core.Utils; +using BDArmory.FX; +using BDArmory.Misc; +using BDArmory.Targeting; +using BDArmory.UI; +using KSP.UI.Screens; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class ModuleWeapon : EngageableWeapon, IBDWeapon + { + #region Declarations + + public static ObjectPool bulletPool; + public static ObjectPool shellPool; + + Coroutine startupRoutine; + Coroutine shutdownRoutine; + + bool finalFire; + + public int rippleIndex = 0; + public string OriginalShortName { get; private set; } + + // WeaponTypes.Cannon is deprecated. identical behavior is achieved with WeaponType.Ballistic and bulletInfo.explosive = true. + public enum WeaponTypes + { + Ballistic, + Cannon, + Laser + } + + public enum WeaponStates + { + Enabled, + Disabled, + PoweringUp, + PoweringDown + } + + public enum BulletDragTypes + { + None, + AnalyticEstimate, + NumericalIntegration + } + + public WeaponStates weaponState = WeaponStates.Disabled; + + //animations + private float fireAnimSpeed = 1; + //is set when setting up animation so it plays a full animation for each shot (animation speed depends on rate of fire) + + public float bulletBallisticCoefficient; + + public WeaponTypes eWeaponType; + + public float heat; + public bool isOverheated; + + private bool wasFiring; + //used for knowing when to stop looped audio clip (when you're not shooting, but you were) + + AudioClip reloadCompleteAudioClip; + AudioClip fireSound; + AudioClip overheatSound; + AudioClip chargeSound; + AudioSource audioSource; + AudioSource audioSource2; + AudioLowPassFilter lowpassFilter; + + private BDStagingAreaGauge gauge; + private int AmmoID; + + //AI + public bool aiControlled = false; + public bool autoFire; + public float autoFireLength = 0; + public float autoFireTimer = 0; + + //used by AI to lead moving targets + private float targetDistance; + private Vector3 targetPosition; + private Vector3 targetVelocity; // local frame velocity + private Vector3 targetAcceleration; // local frame + private Vector3 targetVelocityPrevious; // for acceleration calculation + private Vector3 targetAccelerationPrevious; + private Vector3 relativeVelocity; + Vector3 finalAimTarget; + Vector3 lastFinalAimTarget; + public Vessel visualTargetVessel; + bool targetAcquired; + + public Vector3? FiringSolutionVector => finalAimTarget.IsZero() ? (Vector3?)null : (finalAimTarget - fireTransforms[0].position).normalized; + + public bool recentlyFiring //used by guard to know if it should evaid this + { + get { return Time.time - timeFired < 1; } + } + + //used to reduce volume of audio if multiple guns are being fired (needs to be improved/changed) + //private int numberOfGuns = 0; + + //AI will fire gun if target is within this Cos(angle) of barrel + public float maxAutoFireCosAngle = 0.9993908f; //corresponds to ~2 degrees + + //aimer textures + Vector3 pointingAtPosition; + Vector3 bulletPrediction; + Vector3 fixedLeadOffset = Vector3.zero; + + //gapless particles + List gaplessEmitters = new List(); + + //muzzleflash emitters + List muzzleFlashEmitters; + + //module references + [KSPField] public int turretID = 0; + public ModuleTurret turret; + MissileFire mf; + + public MissileFire weaponManager + { + get + { + if (mf) return mf; + List.Enumerator wm = vessel.FindPartModulesImplementing().GetEnumerator(); + while (wm.MoveNext()) + { + if (wm.Current == null) continue; + mf = wm.Current; + break; + } + wm.Dispose(); + return mf; + } + } + + LineRenderer[] laserRenderers; + + bool pointingAtSelf; //true if weapon is pointing at own vessel + bool userFiring; + Vector3 laserPoint; + public bool slaved; + + public Transform turretBaseTransform + { + get + { + if (turret) + { + return turret.yawTransform.parent; + } + else + { + return fireTransforms[0]; + } + } + } + + public float maxPitch + { + get { return turret ? turret.maxPitch : 0; } + } + + public float minPitch + { + get { return turret ? turret.minPitch : 0; } + } + + public float yawRange + { + get { return turret ? turret.yawRange : 0; } + } + + //weapon interface + public WeaponClasses GetWeaponClass() + { + return WeaponClasses.Gun; + } + + public Part GetPart() + { + return part; + } + + public double ammoCount; + public string ammoLeft; //#191 + + public string GetSubLabel() //I think BDArmorySetup only calls this for the first instance of a particular ShortName, so this probably won't result in a group of n guns having n GetSublabelCalls per frame + { + List.Enumerator craftPart = vessel.parts.GetEnumerator(); + ammoLeft = "Ammo Left: " + ammoCount.ToString("0"); + int lastAmmoID = this.AmmoID; + List.Enumerator weapon = vessel.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + if (weapon.Current.GetShortName() != this.GetShortName()) continue; + if (weapon.Current.AmmoID != this.AmmoID && weapon.Current. AmmoID != lastAmmoID) + { + vessel.GetConnectedResourceTotals(weapon.Current.AmmoID, out double ammoCurrent, out double ammoMax); + ammoLeft += "; " + ammoCurrent.ToString("0"); + lastAmmoID = weapon.Current.AmmoID; + } + } + weapon.Dispose(); + + return ammoLeft; + } + + public string GetMissileType() + { + return string.Empty; + } + +#if DEBUG + Vector3 relVelAdj; + Vector3 accAdj; + Vector3 gravAdj; +#endif + + #endregion Declarations + + #region KSPFields + + [KSPField(isPersistant = true, guiActive = true, guiName = "#LOC_BDArmory_WeaponName", guiActiveEditor = true), UI_Label(affectSymCounterparts = UI_Scene.All, scene = UI_Scene.All)]//Weapon Name + public string WeaponName; + + [KSPField] + public string fireTransformName = "fireTransform"; + public Transform[] fireTransforms; + + [KSPField] + public string shellEjectTransformName = "shellEject"; + public Transform[] shellEjectTransforms; + + [KSPField] + public bool hasDeployAnim = false; + + [KSPField] + public string deployAnimName = "deployAnim"; + AnimationState deployState; + + [KSPField] + public bool hasFireAnimation = false; + + [KSPField] + public string fireAnimName = "fireAnim"; + private AnimationState fireState; + + [KSPField] + public bool spinDownAnimation = false; + private bool spinningDown; + + //weapon specifications + [KSPField] + public float maxTargetingRange = 2000; //max range for raycasting and sighting + + [KSPField] + public float roundsPerMinute = 850; //rate of fire + + [KSPField] + public float maxDeviation = 1; //inaccuracy two standard deviations in degrees (two because backwards compatibility :) + + [KSPField] + public float maxEffectiveDistance = 2500; //used by AI to select appropriate weapon + + [KSPField] + public float bulletMass = 0.3880f; //mass in KG - used for damage and recoil and drag + + [KSPField] + public float caliber = 30; //caliber in mm, used for penetration calcs + + [KSPField] + public float bulletDmgMult = 1; //Used for heat damage modifier for non-explosive bullets + + [KSPField] + public float bulletVelocity = 1030; //velocity in meters/second + + [KSPField] + public float ECPerShot = 0; //EC to use per shot for weapons like railguns + + [KSPField] + public string bulletDragTypeName = "AnalyticEstimate"; + public BulletDragTypes bulletDragType; + + //drag area of the bullet in m^2; equal to Cd * A with A being the frontal area of the bullet; as a first approximation, take Cd to be 0.3 + //bullet mass / bullet drag area. Used in analytic estimate to speed up code + [KSPField] + public float bulletDragArea = 1.209675e-5f; + + private BulletInfo bulletInfo; + + [KSPField] + public string bulletType = "def"; + + [KSPField] + public string ammoName = "50CalAmmo"; //resource usage + + [KSPField] + public float requestResourceAmount = 1; //amount of resource/ammo to deplete per shot + + [KSPField] + public float shellScale = 0.66f; //scale of shell to eject + + [KSPField] + public bool hasRecoil = true; + + [KSPField] + public float recoilReduction = 1; //for reducing recoil on large guns with built in compensation + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_FireLimits"),//Fire Limits + UI_Toggle(disabledText = "#LOC_BDArmory_FireLimits_disabledText", enabledText = "#LOC_BDArmory_FireLimits_enabledText")]//None--In range + public bool onlyFireInRange = true; + //prevent firing when gun's turret is trying to exceed gimbal limits + + [KSPField] + public bool bulletDrop = true; //projectiles are affected by gravity + + [KSPField] + public string weaponType = "ballistic"; + //ballistic, cannon or laser + + [KSPField] + public float laserDamage = 10000; //base damage/second of lasers + + //cannon shell specfications + //TODO: deprectated, moved to bullet config + [KSPField] + public float cannonShellRadius = 30; //max radius of explosion forces/damage + + [KSPField] + public float cannonShellPower = 8; //explosion's impulse force + + [KSPField] + public float cannonShellHeat = -1; //if non-negative, heat damage + + //projectile graphics + [KSPField] + public string projectileColor = "255, 130, 0, 255"; //final color of projectile + Color projectileColorC; + + [KSPField] + public bool fadeColor = false; + + [KSPField] + public string startColor = "255, 160, 0, 200"; + //if fade color is true, projectile starts at this color + + Color startColorC; + + [KSPField] + public float tracerStartWidth = 0.25f; + + [KSPField] + public float tracerEndWidth = 0.2f; + + [KSPField] + public float tracerLength = 0; + //if set to zero, tracer will be the length of the distance covered by the projectile in one physics timestep + + [KSPField] + public float tracerDeltaFactor = 2.65f; + + [KSPField] + public float nonTracerWidth = 0.01f; + + [KSPField] + public int tracerInterval = 0; + + [KSPField] + public float tracerLuminance = 1.75f; + int tracerIntervalCounter; + + [KSPField] + public string bulletTexturePath = "BDArmory/Textures/bullet"; + + [KSPField] + public bool oneShotWorldParticles = false; + + //heat + [KSPField] + public float maxHeat = 3600; + + [KSPField] + public float heatPerShot = 75; + + [KSPField] + public float heatLoss = 250; + + //canon explosion effects + [KSPField] + public string explModelPath = "BDArmory/Models/explosion/explosion"; + + [KSPField] + public string explSoundPath = "BDArmory/Sounds/explode1"; + + //Used for scaling laser damage down based on distance. + [KSPField] + public float tanAngle = 0.0001f; + //Angle of divergeance/2. Theoretical minimum value calculated using θ = (1.22 L/RL)/2, + //where L is laser's wavelength and RL is the radius of the mirror (=gun). + + //audioclip paths + [KSPField] + public string fireSoundPath = "BDArmory/Parts/50CalTurret/sounds/shot"; + + [KSPField] + public string overheatSoundPath = "BDArmory/Parts/50CalTurret/sounds/turretOverheat"; + + [KSPField] + public string chargeSoundPath = "BDArmory/Parts/laserTest/sounds/charge"; + + //audio + [KSPField] + public bool oneShotSound = true; + //play audioclip on every shot, instead of playing looping audio while firing + + [KSPField] + public float soundRepeatTime = 1; + //looped audio will loop back to this time (used for not playing the opening bit, eg the ramp up in pitch of gatling guns) + + [KSPField] + public string reloadAudioPath = string.Empty; + AudioClip reloadAudioClip; + + [KSPField] + public string reloadCompletePath = string.Empty; + + [KSPField] + public bool showReloadMeter = false; //used for cannons or guns with extremely low rate of fire + + //Air Detonating Rounds + [KSPField] + public bool airDetonation = false; + + [KSPField] + public bool proximityDetonation = false; + + [KSPField(isPersistant = true, guiActive = true, guiName = "#LOC_BDArmory_DefaultDetonationRange", guiActiveEditor = false)]//Fuzed Detonation Range + public float defaultDetonationRange = 3500; // maxairDetrange works for altitude fuzing, use this for VT fuzing + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_ProximityFuzeRadius"), UI_FloatRange(minValue = 0f, maxValue = 100f, stepIncrement = 1f, scene = UI_Scene.Editor, affectSymCounterparts = UI_Scene.All)]//Proximity Fuze Radius + public float detonationRange = -1f; // give ability to set proximity range + + [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_MaxDetonationRange"),//Max Detonation Range + UI_FloatRange(minValue = 500, maxValue = 8000f, stepIncrement = 5f, scene = UI_Scene.All)] + public float maxAirDetonationRange = 3500; // could probably get rid of this entirely, max engagement range more or less already does this + + [KSPField] + public bool airDetonationTiming = true; + + //auto proximity tracking + [KSPField] + public float autoProxyTrackRange = 0; + bool atprAcquired; + int aptrTicker; + + float timeFired; + public float initialFireDelay = 0; //used to ripple fire multiple weapons of this type + + [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "#LOC_BDArmory_Barrage")]//Barrage + public bool + useRippleFire = true; + + [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_ToggleBarrage")]//Toggle Barrage + public void ToggleRipple() + { + List.Enumerator craftPart = EditorLogic.fetch.ship.parts.GetEnumerator(); + while (craftPart.MoveNext()) + { + if (craftPart.Current == null) continue; + if (craftPart.Current.name != part.name) continue; + List.Enumerator weapon = craftPart.Current.FindModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (weapon.Current == null) continue; + weapon.Current.useRippleFire = !weapon.Current.useRippleFire; + } + weapon.Dispose(); + } + craftPart.Dispose(); + } + + IEnumerator IncrementRippleIndex(float delay) + { + if (delay > 0) + { + yield return new WaitForSeconds(delay); + } + weaponManager.gunRippleIndex = weaponManager.gunRippleIndex + 1; + + //Debug.Log("incrementing ripple index to: " + weaponManager.gunRippleIndex); + } + + #endregion KSPFields + + #region KSPActions + + [KSPAction("Toggle Weapon")] + public void AGToggle(KSPActionParam param) + { + Toggle(); + } + + [KSPField(guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_Status")]//Status + public string guiStatusString = + "Disabled"; + + //PartWindow buttons + [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "#LOC_BDArmory_Toggle")]//Toggle + public void Toggle() + { + if (weaponState == WeaponStates.Disabled || weaponState == WeaponStates.PoweringDown) + { + EnableWeapon(); + } + else + { + DisableWeapon(); + } + } + + bool agHoldFiring; + + [KSPAction("Fire (Toggle)")] + public void AGFireToggle(KSPActionParam param) + { + agHoldFiring = (param.type == KSPActionType.Activate); + } + + [KSPAction("Fire (Hold)")] + public void AGFireHold(KSPActionParam param) + { + StartCoroutine(FireHoldRoutine(param.group)); + } + + IEnumerator FireHoldRoutine(KSPActionGroup group) + { + KeyBinding key = Misc.Misc.AGEnumToKeybinding(group); + if (key == null) + { + yield break; + } + + while (key.GetKey()) + { + agHoldFiring = true; + yield return null; + } + + agHoldFiring = false; + yield break; + } + + #endregion KSPActions + + #region KSP Events + + public override void OnAwake() + { + base.OnAwake(); + + part.stagingIconAlwaysShown = true; + this.part.stackIconGrouping = StackIconGrouping.SAME_TYPE; + } + + public void Start() + { + part.stagingIconAlwaysShown = true; + this.part.stackIconGrouping = StackIconGrouping.SAME_TYPE; + + Events["HideUI"].active = false; + Events["ShowUI"].active = true; + ParseWeaponType(); + + // extension for feature_engagementenvelope + InitializeEngagementRange(0, maxEffectiveDistance); + if (string.IsNullOrEmpty(GetShortName())) + { + shortName = part.partInfo.title; + } + OriginalShortName = shortName; + WeaponName = shortName; + IEnumerator emitter = part.FindModelComponents().AsEnumerable().GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + emitter.Current.emit = false; + EffectBehaviour.AddParticleEmitter(emitter.Current); + } + emitter.Dispose(); + + if (roundsPerMinute >= 1500) + { + Events["ToggleRipple"].guiActiveEditor = false; + Fields["useRippleFire"].guiActiveEditor = false; + } + vessel.Velocity(); + if (airDetonation) + { + UI_FloatRange detRange = (UI_FloatRange)Fields["maxAirDetonationRange"].uiControlEditor; + detRange.maxValue = maxEffectiveDistance; //altitude fuzing clamped to max range + } + else //disable fuze GUI elements on un-fuzed munitions + { + Fields["maxAirDetonationRange"].guiActive = false; + Fields["maxAirDetonationRange"].guiActiveEditor = false; + Fields["defaultDetonationRange"].guiActive = false; + Fields["defaultDetonationRange"].guiActiveEditor = false; + Fields["detonationRange"].guiActive = false; + Fields["detonationRange"].guiActiveEditor = false; + } + muzzleFlashEmitters = new List(); + IEnumerator mtf = part.FindModelTransforms("muzzleTransform").AsEnumerable().GetEnumerator(); + while (mtf.MoveNext()) + { + if (mtf.Current == null) continue; + KSPParticleEmitter kpe = mtf.Current.GetComponent(); + EffectBehaviour.AddParticleEmitter(kpe); + muzzleFlashEmitters.Add(kpe); + kpe.emit = false; + } + mtf.Dispose(); + + if (HighLogic.LoadedSceneIsFlight) + { + if (eWeaponType != WeaponTypes.Laser) + { + if (bulletPool == null) + { + SetupBulletPool(); + } + if (shellPool == null) + { + SetupShellPool(); + } + } + + //setup transforms + fireTransforms = part.FindModelTransforms(fireTransformName); + shellEjectTransforms = part.FindModelTransforms(shellEjectTransformName); + + //setup emitters + IEnumerator pe = part.FindModelComponents().AsEnumerable().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + pe.Current.maxSize *= part.rescaleFactor; + pe.Current.minSize *= part.rescaleFactor; + pe.Current.shape3D *= part.rescaleFactor; + pe.Current.shape2D *= part.rescaleFactor; + pe.Current.shape1D *= part.rescaleFactor; + + if (pe.Current.useWorldSpace && !oneShotWorldParticles) + { + BDAGaplessParticleEmitter gpe = pe.Current.gameObject.AddComponent(); + gpe.part = part; + gaplessEmitters.Add(gpe); + } + else + { + EffectBehaviour.AddParticleEmitter(pe.Current); + } + } + pe.Dispose(); + + //setup projectile colors + projectileColorC = Misc.Misc.ParseColor255(projectileColor); + startColorC = Misc.Misc.ParseColor255(startColor); + + //init and zero points + targetPosition = Vector3.zero; + pointingAtPosition = Vector3.zero; + bulletPrediction = Vector3.zero; + + //setup audio + SetupAudio(); + + // Setup gauges + gauge = (BDStagingAreaGauge)part.AddModule("BDStagingAreaGauge"); + gauge.AmmoName = ammoName; + gauge.AudioSource = audioSource; + gauge.ReloadAudioClip = reloadAudioClip; + gauge.ReloadCompleteAudioClip = reloadCompleteAudioClip; + + AmmoID = PartResourceLibrary.Instance.GetDefinition(ammoName).id; + + //laser setup + if (eWeaponType == WeaponTypes.Laser) + { + SetupLaserSpecifics(); + if (maxTargetingRange < maxEffectiveDistance) + { + maxEffectiveDistance = maxTargetingRange; + } + } + } + else if (HighLogic.LoadedSceneIsEditor) + { + fireTransforms = part.FindModelTransforms(fireTransformName); + WeaponNameWindow.OnActionGroupEditorOpened.Add(OnActionGroupEditorOpened); + WeaponNameWindow.OnActionGroupEditorClosed.Add(OnActionGroupEditorClosed); + } + //turret setup + List.Enumerator turr = part.FindModulesImplementing().GetEnumerator(); + while (turr.MoveNext()) + { + if (turr.Current == null) continue; + if (turr.Current.turretID != turretID) continue; + turret = turr.Current; + turret.SetReferenceTransform(fireTransforms[0]); + break; + } + turr.Dispose(); + + if (!turret) + { + Fields["onlyFireInRange"].guiActive = false; + Fields["onlyFireInRange"].guiActiveEditor = false; + } + + //setup animations + if (hasDeployAnim) + { + deployState = Misc.Misc.SetUpSingleAnimation(deployAnimName, part); + deployState.normalizedTime = 0; + deployState.speed = 0; + deployState.enabled = true; + } + if (hasFireAnimation) + { + fireState = Misc.Misc.SetUpSingleAnimation(fireAnimName, part); + fireState.enabled = false; + } + + SetupBullet(); + SetInitialDetonationDistance(); + if (bulletInfo == null) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: Failed To load bullet : " + bulletType); + } + else + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.Log("[BDArmory]: BulletType Loaded : " + bulletType); + } + + BDArmorySetup.OnVolumeChange += UpdateVolume; + } + + void OnDestroy() + { + BDArmorySetup.OnVolumeChange -= UpdateVolume; + WeaponNameWindow.OnActionGroupEditorOpened.Remove(OnActionGroupEditorOpened); + WeaponNameWindow.OnActionGroupEditorClosed.Remove(OnActionGroupEditorClosed); + } + + void Update() + { + if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && vessel.IsControllable) + { + if (lowpassFilter) + { + if (InternalCamera.Instance && InternalCamera.Instance.isActive) + { + lowpassFilter.enabled = true; + } + else + { + lowpassFilter.enabled = false; + } + } + + if (weaponState == WeaponStates.Enabled && + (TimeWarp.WarpMode != TimeWarp.Modes.HIGH || TimeWarp.CurrentRate == 1)) + { + userFiring = (BDInputUtils.GetKey(BDInputSettingsFields.WEAP_FIRE_KEY) && + (vessel.isActiveVessel || BDArmorySettings.REMOTE_SHOOTING) && !MapView.MapIsEnabled && + !aiControlled); + if ((userFiring || autoFire || agHoldFiring) && + (yawRange == 0 || (maxPitch - minPitch) == 0 || + turret.TargetInRange(finalAimTarget, 10, float.MaxValue))) + { + if (useRippleFire && (pointingAtSelf || isOverheated)) + { + StartCoroutine(IncrementRippleIndex(0)); + finalFire = false; + } + else if (eWeaponType == WeaponTypes.Ballistic || eWeaponType == WeaponTypes.Cannon) //WeaponTypes.Cannon is deprecated + { + finalFire = true; + } + } + else + { + if (spinDownAnimation) spinningDown = true; + if (eWeaponType == WeaponTypes.Laser) audioSource.Stop(); + if (!oneShotSound && wasFiring) + { + audioSource.Stop(); + wasFiring = false; + audioSource2.PlayOneShot(overheatSound); + } + } + } + else + { + audioSource.Stop(); + autoFire = false; + } + + if (spinningDown && spinDownAnimation && hasFireAnimation) + { + if (fireState.normalizedTime > 1) fireState.normalizedTime = 0; + fireState.speed = fireAnimSpeed; + fireAnimSpeed = Mathf.Lerp(fireAnimSpeed, 0, 0.04f); + } + + // Draw gauges + if (vessel.isActiveVessel) + { + vessel.GetConnectedResourceTotals(AmmoID, out double ammoCurrent, out double ammoMax); + gauge.UpdateAmmoMeter((float)(ammoCurrent / ammoMax)); + + if (showReloadMeter) + { + gauge.UpdateReloadMeter((Time.time - timeFired) * roundsPerMinute / 60); + } + else + { + gauge.UpdateHeatMeter(heat / maxHeat); + } + } + } + } + + void FixedUpdate() + { + if (HighLogic.LoadedSceneIsFlight && !vessel.packed) + { + if (!vessel.IsControllable) + { + if (weaponState != WeaponStates.PoweringDown || weaponState != WeaponStates.Disabled) + { + DisableWeapon(); + } + return; + } + + UpdateHeat(); + if (weaponState == WeaponStates.Enabled && + (TimeWarp.WarpMode != TimeWarp.Modes.HIGH || TimeWarp.CurrentRate == 1)) + { + //Aim(); + StartCoroutine(AimAndFireAtEndOfFrame()); + + if (eWeaponType == WeaponTypes.Laser) + { + if ((userFiring || autoFire || agHoldFiring) && + (!turret || turret.TargetInRange(targetPosition, 10, float.MaxValue))) + { + finalFire = true; + } + else + { + for (int i = 0; i < laserRenderers.Length; i++) + { + laserRenderers[i].enabled = false; + } + audioSource.Stop(); + } + } + } + else if (eWeaponType == WeaponTypes.Laser) + { + for (int i = 0; i < laserRenderers.Length; i++) + { + laserRenderers[i].enabled = false; + } + audioSource.Stop(); + } + } + lastFinalAimTarget = finalAimTarget; + } + + private void UpdateMenus(bool visible) + { + Events["HideUI"].active = visible; + Events["ShowUI"].active = !visible; + } + + private void OnActionGroupEditorOpened() + { + Events["HideUI"].active = false; + Events["ShowUI"].active = false; + } + + private void OnActionGroupEditorClosed() + { + Events["HideUI"].active = false; + Events["ShowUI"].active = true; + } + + [KSPEvent(guiActiveEditor = true, guiName = "#LOC_BDArmory_HideWeaponGroupUI", active = false)]//Hide Weapon Group UI + public void HideUI() + { + WeaponGroupWindow.HideGUI(); + UpdateMenus(false); + } + + [KSPEvent(guiActiveEditor = true, guiName = "#LOC_BDArmory_SetWeaponGroupUI", active = false)]//Set Weapon Group UI + public void ShowUI() + { + WeaponGroupWindow.ShowGUI(this); + UpdateMenus(true); + } + + void OnGUI() + { + if (weaponState == WeaponStates.Enabled && vessel && !vessel.packed && vessel.isActiveVessel && + BDArmorySettings.DRAW_AIMERS && !aiControlled && !MapView.MapIsEnabled && !pointingAtSelf) + { + float size = 30; + + Vector3 reticlePosition; + if (BDArmorySettings.AIM_ASSIST) + { + if (targetAcquired && (slaved || yawRange < 1 || maxPitch - minPitch < 1)) + { + reticlePosition = pointingAtPosition + fixedLeadOffset; + + if (!slaved) + { + BDGUIUtils.DrawLineBetweenWorldPositions(pointingAtPosition, reticlePosition, 2, + new Color(0, 1, 0, 0.6f)); + } + + BDGUIUtils.DrawTextureOnWorldPos(pointingAtPosition, BDArmorySetup.Instance.greenDotTexture, + new Vector2(6, 6), 0); + + if (atprAcquired) + { + BDGUIUtils.DrawTextureOnWorldPos(targetPosition, BDArmorySetup.Instance.openGreenSquare, + new Vector2(20, 20), 0); + } + } + else + { + reticlePosition = bulletPrediction; + } + } + else + { + reticlePosition = pointingAtPosition; + } + + Texture2D texture; + if (Vector3.Angle(pointingAtPosition - transform.position, finalAimTarget - transform.position) < 1f) + { + texture = BDArmorySetup.Instance.greenSpikedPointCircleTexture; + } + else + { + texture = BDArmorySetup.Instance.greenPointCircleTexture; + } + BDGUIUtils.DrawTextureOnWorldPos(reticlePosition, texture, new Vector2(size, size), 0); + + if (BDArmorySettings.DRAW_DEBUG_LINES) + { + if (targetAcquired) + { + BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position, targetPosition, 2, + Color.blue); + } + } + } + + if (HighLogic.LoadedSceneIsEditor && BDArmorySetup.showWeaponAlignment) + { + DrawAlignmentIndicator(); + } + +#if DEBUG + if (BDArmorySettings.DRAW_DEBUG_LINES && weaponState == WeaponStates.Enabled && vessel && !vessel.packed && !MapView.MapIsEnabled) + { + BDGUIUtils.MarkPosition(targetPosition, transform, Color.cyan); + BDGUIUtils.DrawLineBetweenWorldPositions(targetPosition, targetPosition + relVelAdj, 2, Color.green); + BDGUIUtils.DrawLineBetweenWorldPositions(targetPosition + relVelAdj, targetPosition + relVelAdj + accAdj, 2, Color.magenta); + BDGUIUtils.DrawLineBetweenWorldPositions(targetPosition + relVelAdj + accAdj, targetPosition + relVelAdj + accAdj + gravAdj, 2, Color.yellow); + BDGUIUtils.MarkPosition(finalAimTarget, transform, Color.cyan, size: 4); + } +#endif + } + + #endregion KSP Events + + #region Fire + + private void Fire() + { + if (BDArmorySetup.GameIsPaused) + { + if (audioSource.isPlaying) + { + audioSource.Stop(); + } + return; + } + + float timeGap = (60 / roundsPerMinute) * TimeWarp.CurrentRate; + if (Time.time - timeFired > timeGap + && !isOverheated + && !pointingAtSelf + && (aiControlled || !Misc.Misc.CheckMouseIsOnGui()) + && WMgrAuthorized()) + { + bool effectsShot = false; + //Transform[] fireTransforms = part.FindModelTransforms("fireTransform"); + for (float iTime = Mathf.Min(Time.time - timeFired - timeGap, TimeWarp.fixedDeltaTime); iTime >= 0; iTime -= timeGap) + for (int i = 0; i < fireTransforms.Length; i++) + { + //if ((BDArmorySettings.INFINITE_AMMO || part.RequestResource(ammoName, requestResourceAmount) > 0)) + if (CanFire()) + { + Transform fireTransform = fireTransforms[i]; + spinningDown = false; + + //recoil + if (hasRecoil) + { + part.rb.AddForceAtPosition((-fireTransform.forward) * (bulletVelocity * bulletMass / 1000 * BDArmorySettings.RECOIL_FACTOR * recoilReduction), + fireTransform.position, ForceMode.Impulse); + } + + if (!effectsShot) + { + //sound + if (oneShotSound) + { + audioSource.Stop(); + audioSource.PlayOneShot(fireSound); + } + else + { + wasFiring = true; + if (!audioSource.isPlaying) + { + audioSource.clip = fireSound; + audioSource.loop = false; + audioSource.time = 0; + audioSource.Play(); + } + else + { + if (audioSource.time >= fireSound.length) + { + audioSource.time = soundRepeatTime; + } + } + } + + //animation + if (hasFireAnimation) + { + float unclampedSpeed = (roundsPerMinute * fireState.length) / 60f; + float lowFramerateFix = 1; + if (roundsPerMinute > 500f) + { + lowFramerateFix = (0.02f / Time.deltaTime); + } + fireAnimSpeed = Mathf.Clamp(unclampedSpeed, 1f * lowFramerateFix, 20f * lowFramerateFix); + fireState.enabled = true; + if (unclampedSpeed == fireAnimSpeed || fireState.normalizedTime > 1) + { + fireState.normalizedTime = 0; + } + fireState.speed = fireAnimSpeed; + fireState.normalizedTime = Mathf.Repeat(fireState.normalizedTime, 1); + + //Debug.Log("fireAnim time: " + fireState.normalizedTime + ", speed; " + fireState.speed); + } + + //muzzle flash + List.Enumerator pEmitter = muzzleFlashEmitters.GetEnumerator(); + while (pEmitter.MoveNext()) + { + if (pEmitter.Current == null) continue; + //KSPParticleEmitter pEmitter = mtf.gameObject.GetComponent(); + if (pEmitter.Current.useWorldSpace && !oneShotWorldParticles) continue; + if (pEmitter.Current.maxEnergy < 0.5f) + { + float twoFrameTime = Mathf.Clamp(Time.deltaTime * 2f, 0.02f, 0.499f); + pEmitter.Current.maxEnergy = twoFrameTime; + pEmitter.Current.minEnergy = twoFrameTime / 3f; + } + pEmitter.Current.Emit(); + } + pEmitter.Dispose(); + + List.Enumerator gpe = gaplessEmitters.GetEnumerator(); + while (gpe.MoveNext()) + { + if (gpe.Current == null) continue; + gpe.Current.EmitParticles(); + } + gpe.Dispose(); + + //shell ejection + if (BDArmorySettings.EJECT_SHELLS) + { + IEnumerator sTf = shellEjectTransforms.AsEnumerable().GetEnumerator(); + while (sTf.MoveNext()) + { + if (sTf.Current == null) continue; + GameObject ejectedShell = shellPool.GetPooledObject(); + ejectedShell.transform.position = sTf.Current.position; + //+(part.rb.velocity*TimeWarp.fixedDeltaTime); + ejectedShell.transform.rotation = sTf.Current.rotation; + ejectedShell.transform.localScale = Vector3.one * shellScale; + ShellCasing shellComponent = ejectedShell.GetComponent(); + shellComponent.initialV = part.rb.velocity; + ejectedShell.SetActive(true); + } + sTf.Dispose(); + } + effectsShot = true; + } + + //firing bullet + GameObject firedBullet = bulletPool.GetPooledObject(); + PooledBullet pBullet = firedBullet.GetComponent(); + + firedBullet.transform.position = fireTransform.position; + + pBullet.caliber = bulletInfo.caliber; + pBullet.bulletVelocity = bulletInfo.bulletVelocity; + pBullet.bulletMass = bulletInfo.bulletMass; + pBullet.explosive = bulletInfo.explosive; + pBullet.apBulletMod = bulletInfo.apBulletMod; + pBullet.bulletDmgMult = bulletDmgMult; + + //A = π x (Ø / 2)^2 + bulletDragArea = Mathf.PI * Mathf.Pow(caliber / 2f, 2f); + + //Bc = m/Cd * A + bulletBallisticCoefficient = bulletMass / ((bulletDragArea / 1000000f) * 0.295f); // mm^2 to m^2 + + //Bc = m/d^2 * i where i = 0.484 + //bulletBallisticCoefficient = bulletMass / Mathf.Pow(caliber / 1000, 2f) * 0.484f; + + pBullet.ballisticCoefficient = bulletBallisticCoefficient; + + pBullet.flightTimeElapsed = iTime; + // measure bullet lifetime in time rather than in distance, because distances get very relative in orbit + pBullet.timeToLiveUntil = Mathf.Max(maxTargetingRange, maxEffectiveDistance) / bulletVelocity * 1.1f + Time.time; + + timeFired = Time.time - iTime; + + Vector3 firedVelocity = + VectorUtils.GaussianDirectionDeviation(fireTransform.forward, maxDeviation / 4) * bulletVelocity; + + pBullet.currentVelocity = (part.rb.velocity + Krakensbane.GetFrameVelocityV3f()) + firedVelocity; // use the real velocity, w/o offloading + firedBullet.transform.position += (part.rb.velocity + Krakensbane.GetFrameVelocityV3f()) * Time.fixedDeltaTime + + pBullet.currentVelocity * iTime; + + pBullet.sourceVessel = vessel; + pBullet.bulletTexturePath = bulletTexturePath; + pBullet.projectileColor = projectileColorC; + pBullet.startColor = startColorC; + pBullet.fadeColor = fadeColor; + tracerIntervalCounter++; + if (tracerIntervalCounter > tracerInterval) + { + tracerIntervalCounter = 0; + pBullet.tracerStartWidth = tracerStartWidth; + pBullet.tracerEndWidth = tracerEndWidth; + } + else + { + pBullet.tracerStartWidth = nonTracerWidth; + pBullet.tracerEndWidth = nonTracerWidth; + pBullet.startColor.a *= 0.5f; + pBullet.projectileColor.a *= 0.5f; + } + pBullet.tracerLength = tracerLength; + pBullet.tracerDeltaFactor = tracerDeltaFactor; + pBullet.tracerLuminance = tracerLuminance; + pBullet.bulletDrop = bulletDrop; + + if ((eWeaponType == WeaponTypes.Ballistic && bulletInfo.explosive) || eWeaponType == WeaponTypes.Cannon) //WeaponTypes.Cannon is deprecated + { + if (bulletType == "def") + { + //legacy model, per weapon config + pBullet.bulletType = PooledBullet.PooledBulletTypes.Explosive; + pBullet.explModelPath = explModelPath; + pBullet.explSoundPath = explSoundPath; + pBullet.blastPower = cannonShellPower; + pBullet.blastHeat = cannonShellHeat; + pBullet.radius = cannonShellRadius; + pBullet.airDetonation = airDetonation; + pBullet.detonationRange = detonationRange; + pBullet.maxAirDetonationRange = maxAirDetonationRange; + pBullet.defaultDetonationRange = defaultDetonationRange; + pBullet.proximityDetonation = proximityDetonation; + } + else + { + //use values from bullets.cfg + pBullet.bulletType = PooledBullet.PooledBulletTypes.Explosive; + pBullet.explModelPath = explModelPath; + pBullet.explSoundPath = explSoundPath; + + pBullet.tntMass = bulletInfo.tntMass; + pBullet.blastPower = bulletInfo.blastPower; + pBullet.blastHeat = bulletInfo.blastHeat; + pBullet.radius = bulletInfo.blastRadius; + + pBullet.airDetonation = airDetonation; + pBullet.detonationRange = detonationRange; + pBullet.maxAirDetonationRange = maxAirDetonationRange; + pBullet.defaultDetonationRange = defaultDetonationRange; + pBullet.proximityDetonation = proximityDetonation; + } + } + else + { + pBullet.bulletType = PooledBullet.PooledBulletTypes.Standard; + pBullet.airDetonation = false; + } + switch (bulletDragType) + { + case BulletDragTypes.None: + pBullet.dragType = PooledBullet.BulletDragTypes.None; + break; + + case BulletDragTypes.AnalyticEstimate: + pBullet.dragType = PooledBullet.BulletDragTypes.AnalyticEstimate; + break; + + case BulletDragTypes.NumericalIntegration: + pBullet.dragType = PooledBullet.BulletDragTypes.NumericalIntegration; + break; + } + + pBullet.bullet = BulletInfo.bullets[bulletType]; + pBullet.gameObject.SetActive(true); + + //heat + heat += heatPerShot; + //EC + DrainECPerShot(); + } + else + { + spinningDown = true; + if (!oneShotSound && wasFiring) + { + audioSource.Stop(); + wasFiring = false; + audioSource2.PlayOneShot(overheatSound); + } + } + } + + if (useRippleFire) + { + StartCoroutine(IncrementRippleIndex(initialFireDelay * TimeWarp.CurrentRate)); + } + } + else + { + spinningDown = true; + } + } + + private bool FireLaser() + { + float chargeAmount = requestResourceAmount * TimeWarp.fixedDeltaTime; + + if (!pointingAtSelf && !Misc.Misc.CheckMouseIsOnGui() && WMgrAuthorized() && !isOverheated && + (part.RequestResource(ammoName.GetHashCode(), (double)chargeAmount) >= chargeAmount || BDArmorySettings.INFINITE_AMMO)) + { + if (!audioSource.isPlaying) + { + audioSource.PlayOneShot(chargeSound); + audioSource.Play(); + audioSource.loop = true; + } + for (int i = 0; i < fireTransforms.Length; i++) + { + Transform tf = fireTransforms[i]; + + LineRenderer lr = laserRenderers[i]; + + Vector3 rayDirection = tf.forward; + + Vector3 targetDirection = Vector3.zero; //autoTrack enhancer + Vector3 targetDirectionLR = tf.forward; + + if (((visualTargetVessel != null && visualTargetVessel.loaded) || slaved) + && Vector3.Angle(rayDirection, targetDirection) < 1) + { + targetDirection = targetPosition - tf.position; + rayDirection = targetDirection; + targetDirectionLR = targetDirection.normalized; + } + + Ray ray = new Ray(tf.position, rayDirection); + lr.useWorldSpace = false; + lr.SetPosition(0, Vector3.zero); + RaycastHit hit; + + if (Physics.Raycast(ray, out hit, maxTargetingRange, 9076737)) + { + lr.useWorldSpace = true; + laserPoint = hit.point + targetVelocity * Time.fixedDeltaTime; + + lr.SetPosition(0, tf.position + (part.rb.velocity * Time.fixedDeltaTime)); + lr.SetPosition(1, laserPoint); + + KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards(); + Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent(); + + if (p && p.vessel && p.vessel != vessel) + { + float distance = hit.distance; + //Scales down the damage based on the increased surface area of the area being hit by the laser. Think flashlight on a wall. + p.AddDamage(laserDamage / (1 + Mathf.PI * Mathf.Pow(tanAngle * distance, 2)) * + TimeWarp.fixedDeltaTime + * 0.425f); + + if (BDArmorySettings.INSTAKILL) p.Destroy(); + } + + if (Time.time - timeFired > 6 / 120 && BDArmorySettings.BULLET_HITS) + { + BulletHitFX.CreateBulletHit(p, laserPoint, hit, hit.normal, false, 0, 0); + } + } + else + { + laserPoint = lr.transform.InverseTransformPoint((targetDirectionLR * maxTargetingRange) + tf.position); + lr.SetPosition(1, laserPoint); + } + } + heat += heatPerShot * TimeWarp.CurrentRate; + return true; + } + else + { + return false; + } + } + + void SetupLaserSpecifics() + { + chargeSound = GameDatabase.Instance.GetAudioClip(chargeSoundPath); + if (HighLogic.LoadedSceneIsFlight) + { + audioSource.clip = fireSound; + } + + laserRenderers = new LineRenderer[fireTransforms.Length]; + + for (int i = 0; i < fireTransforms.Length; i++) + { + Transform tf = fireTransforms[i]; + laserRenderers[i] = tf.gameObject.AddComponent(); + Color laserColor = Misc.Misc.ParseColor255(projectileColor); + laserColor.a = laserColor.a / 2; + laserRenderers[i].material = new Material(Shader.Find("KSP/Particles/Alpha Blended")); + laserRenderers[i].material.SetColor("_TintColor", laserColor); + laserRenderers[i].material.mainTexture = GameDatabase.Instance.GetTexture("BDArmory/Textures/laser", false); + laserRenderers[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; //= false; + laserRenderers[i].receiveShadows = false; + laserRenderers[i].startWidth = tracerStartWidth; + laserRenderers[i].endWidth = tracerEndWidth; + laserRenderers[i].positionCount = 2; + laserRenderers[i].SetPosition(0, Vector3.zero); + laserRenderers[i].SetPosition(1, Vector3.zero); + laserRenderers[i].useWorldSpace = false; + laserRenderers[i].enabled = false; + } + } + + bool WMgrAuthorized() + { + MissileFire manager = BDArmorySetup.Instance.ActiveWeaponManager; + if (manager != null && manager.vessel == vessel) + { + if (manager.hasSingleFired) return false; + else return true; + } + else + { + return true; + } + } + + void CheckWeaponSafety() + { + pointingAtSelf = false; + + // While I'm not saying vessels larger than 500m are impossible, let's be practical here + const float maxCheckRange = 500f; + float checkRange = Mathf.Min(targetAcquired ? targetDistance : maxTargetingRange, maxCheckRange); + + for (int i = 0; i < fireTransforms.Length; i++) + { + Ray ray = new Ray(fireTransforms[i].position, fireTransforms[i].forward); + RaycastHit hit; + + if (Physics.Raycast(ray, out hit, maxTargetingRange, 9076737)) + { + KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards(); + Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent(); + if (p && p.vessel && p.vessel == vessel) + { + pointingAtSelf = true; + break; + } + } + + pointingAtPosition = fireTransforms[i].position + (ray.direction * targetDistance); + } + } + + public void EnableWeapon() + { + if (weaponState == WeaponStates.Enabled || weaponState == WeaponStates.PoweringUp) + { + return; + } + + StopShutdownStartupRoutines(); + + startupRoutine = StartCoroutine(StartupRoutine()); + } + + public void DisableWeapon() + { + if (weaponState == WeaponStates.Disabled || weaponState == WeaponStates.PoweringDown) + { + return; + } + + StopShutdownStartupRoutines(); + + shutdownRoutine = StartCoroutine(ShutdownRoutine()); + } + + void ParseWeaponType() + { + weaponType = weaponType.ToLower(); + + switch (weaponType) + { + case "ballistic": + eWeaponType = WeaponTypes.Ballistic; + break; + + case "cannon": + // Note: this type is deprecated. behavior is duplicated with Ballistic and bulletInfo.explosive = true + // Type remains for backward compatability for now. + eWeaponType = WeaponTypes.Cannon; + break; + + case "laser": + eWeaponType = WeaponTypes.Laser; + break; + } + } + + void DrainECPerShot() + { + if (ECPerShot == 0) return; + //double drainAmount = ECPerShot * TimeWarp.fixedDeltaTime; + double drainAmount = ECPerShot; + double chargeAvailable = part.RequestResource("ElectricCharge", drainAmount, ResourceFlowMode.ALL_VESSEL); + } + + bool CanFire() + { + if (ECPerShot != 0) + { + double chargeAvailable = part.RequestResource("ElectricCharge", ECPerShot, ResourceFlowMode.ALL_VESSEL); + if (chargeAvailable < ECPerShot * 0.95f) + { + ScreenMessages.PostScreenMessage("Weapon Requires EC", 5.0f, ScreenMessageStyle.UPPER_CENTER); + return false; + } + } + + if ((BDArmorySettings.INFINITE_AMMO || part.RequestResource(ammoName.GetHashCode(), (double)requestResourceAmount) > 0)) + { + return true; + } + + return false; + } + + #endregion Fire + + #region Audio + + void UpdateVolume() + { + if (audioSource) + { + audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + if (audioSource2) + { + audioSource2.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + if (lowpassFilter) + { + lowpassFilter.cutoffFrequency = BDArmorySettings.IVA_LOWPASS_FREQ; + } + } + + void SetupAudio() + { + fireSound = GameDatabase.Instance.GetAudioClip(fireSoundPath); + overheatSound = GameDatabase.Instance.GetAudioClip(overheatSoundPath); + if (!audioSource) + { + audioSource = gameObject.AddComponent(); + audioSource.bypassListenerEffects = true; + audioSource.minDistance = .3f; + audioSource.maxDistance = 1000; + audioSource.priority = 10; + audioSource.dopplerLevel = 0; + audioSource.spatialBlend = 1; + } + + if (!audioSource2) + { + audioSource2 = gameObject.AddComponent(); + audioSource2.bypassListenerEffects = true; + audioSource2.minDistance = .3f; + audioSource2.maxDistance = 1000; + audioSource2.dopplerLevel = 0; + audioSource2.priority = 10; + audioSource2.spatialBlend = 1; + } + + if (reloadAudioPath != string.Empty) + { + reloadAudioClip = (AudioClip)GameDatabase.Instance.GetAudioClip(reloadAudioPath); + } + if (reloadCompletePath != string.Empty) + { + reloadCompleteAudioClip = (AudioClip)GameDatabase.Instance.GetAudioClip(reloadCompletePath); + } + + if (!lowpassFilter && gameObject.GetComponents().Length == 0) + { + lowpassFilter = gameObject.AddComponent(); + lowpassFilter.cutoffFrequency = BDArmorySettings.IVA_LOWPASS_FREQ; + lowpassFilter.lowpassResonanceQ = 1f; + } + + UpdateVolume(); + } + + #endregion Audio + + #region Targeting + + void Aim() + { + //AI control + if (aiControlled && !slaved) + { + if (!targetAcquired) + { + autoFire = false; + return; + } + } + + if (!slaved && !aiControlled && (yawRange > 0 || maxPitch - minPitch > 0)) + { + //MouseControl + Vector3 mouseAim = new Vector3(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, + 0); + Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mouseAim); + RaycastHit hit; + + if (Physics.Raycast(ray, out hit, maxTargetingRange, 9076737)) + { + targetPosition = hit.point; + + //aim through self vessel if occluding mouseray + + KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards(); + Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent(); + + if (p && p.vessel && p.vessel == vessel) + { + targetPosition = ray.direction * maxTargetingRange + + FlightCamera.fetch.mainCamera.transform.position; + } + } + else + { + targetPosition = (ray.direction * (maxTargetingRange + (FlightCamera.fetch.Distance * 0.75f))) + + FlightCamera.fetch.mainCamera.transform.position; + if (visualTargetVessel != null && visualTargetVessel.loaded) + { + targetPosition = ray.direction * + Vector3.Distance(visualTargetVessel.transform.position, + FlightCamera.fetch.mainCamera.transform.position) + + FlightCamera.fetch.mainCamera.transform.position; + } + } + } + + //aim assist + Vector3 finalTarget = targetPosition; + Vector3 originalTarget = targetPosition; + targetDistance = Vector3.Distance(finalTarget, fireTransforms[0].position); + + if ((BDArmorySettings.AIM_ASSIST || aiControlled) && eWeaponType != WeaponTypes.Laser) + { + float effectiveVelocity = bulletVelocity; + Vector3 relativeVelocity = targetVelocity - part.rb.velocity; + Quaternion.FromToRotation(targetAccelerationPrevious, targetAcceleration).ToAngleAxis(out float accelDAngle, out Vector3 accelDAxis); + + Vector3 leadTarget = targetPosition; + + int iterations = 6; + while (--iterations >= 0) + { + finalTarget = targetPosition; + float time = (leadTarget - fireTransforms[0].position).magnitude / effectiveVelocity - (Time.fixedDeltaTime * 1.5f); + + if (targetAcquired) + { + finalTarget += relativeVelocity * time; +#if DEBUG + relVelAdj = relativeVelocity * time; + var vc = finalTarget; +#endif + var accelDExtAngle = accelDAngle * time / 3; + var extrapolatedAcceleration = + Quaternion.AngleAxis(accelDExtAngle, accelDAxis) + * targetAcceleration + * Mathf.Cos(accelDExtAngle * Mathf.Deg2Rad * 2.222f); + finalTarget += 0.5f * extrapolatedAcceleration * time * time; +#if DEBUG + accAdj = (finalTarget - vc); +#endif + } + else if (Misc.Misc.GetRadarAltitudeAtPos(targetPosition) < 2000) + { + //this vessel velocity compensation against stationary + finalTarget += (-(part.rb.velocity + Krakensbane.GetFrameVelocityV3f()) * time); + } + + leadTarget = finalTarget; + + if (bulletDrop) + { +#if DEBUG + var vc = finalTarget; +#endif + Vector3 up = (VectorUtils.GetUpDirection(finalTarget) + 2 * VectorUtils.GetUpDirection(fireTransforms[0].position)).normalized; + float gAccel = ((float)FlightGlobals.getGeeForceAtPosition(finalTarget).magnitude + + (float)FlightGlobals.getGeeForceAtPosition(fireTransforms[0].position).magnitude * 2) / 3; + Vector3 intermediateTarget = finalTarget + (0.5f * gAccel * time * time * up); + + var avGrav = (FlightGlobals.getGeeForceAtPosition(finalTarget) + 2 * FlightGlobals.getGeeForceAtPosition(fireTransforms[0].position)) / 3; + effectiveVelocity = bulletVelocity + * (float)Vector3d.Dot((intermediateTarget - fireTransforms[0].position).normalized, (finalTarget - fireTransforms[0].position).normalized) + + Vector3.Project(avGrav, finalTarget - fireTransforms[0].position).magnitude * time / 2 * (Vector3.Dot(avGrav, finalTarget - fireTransforms[0].position) < 0 ? -1 : 1); + finalTarget = intermediateTarget; +#if DEBUG + gravAdj = (finalTarget - vc); +#endif + } + } + + targetDistance = Vector3.Distance(finalTarget, fireTransforms[0].position); + fixedLeadOffset = originalTarget - finalTarget; //for aiming fixed guns to moving target + + //airdetonation + if (airDetonation) + { + if (targetAcquired && airDetonationTiming) + { + //detonationRange = BlastPhysicsUtils.CalculateBlastRange(bulletInfo.tntMass); //this returns 0, use detonationRange GUI tweakable instead + defaultDetonationRange = targetDistance;// adds variable time fuze if/when proximity fuzes fail + } + else + { + //detonationRange = defaultDetonationRange; + defaultDetonationRange = maxAirDetonationRange; //airburst at max range + } + } + } + + //removed the detonationange += UnityEngine.random, that gets called every frame and just causes the prox fuze range to wander + + finalAimTarget = finalTarget; + + //final turret aiming + if (slaved && !targetAcquired) return; + if (turret) + { + bool origSmooth = turret.smoothRotation; + if (aiControlled || slaved) + { + turret.smoothRotation = false; + } + turret.AimToTarget(finalTarget); + turret.smoothRotation = origSmooth; + } + } + + void CheckAIAutofire() + { + //autofiring with AI + if (targetAcquired && aiControlled) + { + Transform fireTransform = fireTransforms[0]; + Vector3 targetRelPos = (finalAimTarget) - fireTransform.position; + Vector3 aimDirection = fireTransform.forward; + float targetCosAngle = Vector3.Dot(aimDirection, targetRelPos.normalized); + + Vector3 targetDiffVec = finalAimTarget - lastFinalAimTarget; + Vector3 projectedTargetPos = targetDiffVec; + //projectedTargetPos /= TimeWarp.fixedDeltaTime; + //projectedTargetPos *= TimeWarp.fixedDeltaTime; + projectedTargetPos *= 2; //project where the target will be in 2 timesteps + projectedTargetPos += finalAimTarget; + + targetDiffVec.Normalize(); + Vector3 lastTargetRelPos = (lastFinalAimTarget) - fireTransform.position; + + if (BDATargetManager.CheckSafeToFireGuns(weaponManager, aimDirection, 1000, 0.999848f) //~1 degree of unsafe angle + && targetCosAngle >= maxAutoFireCosAngle) //check if directly on target + { + autoFire = true; + } + else + { + autoFire = false; + } + } + else + { + autoFire = false; + } + + //disable autofire after burst length + if (autoFire && Time.time - autoFireTimer > autoFireLength) + { + autoFire = false; + visualTargetVessel = null; + } + } + + IEnumerator AimAndFireAtEndOfFrame() + { + if (eWeaponType != WeaponTypes.Laser) yield return new WaitForEndOfFrame(); + + UpdateTargetVessel(); + updateAcceleration(targetVelocity, targetPosition); + relativeVelocity = targetVelocity - vessel.rb_velocity; + + RunTrajectorySimulation(); + Aim(); + CheckWeaponSafety(); + CheckAIAutofire(); + + if (finalFire) + { + if (eWeaponType == WeaponTypes.Laser) + { + if (FireLaser()) + { + for (int i = 0; i < laserRenderers.Length; i++) + { + laserRenderers[i].enabled = true; + } + } + else + { + for (int i = 0; i < laserRenderers.Length; i++) + { + laserRenderers[i].enabled = false; + } + audioSource.Stop(); + } + } + else + { + if (useRippleFire && weaponManager.gunRippleIndex != rippleIndex) + { + //timeFired = Time.time + (initialFireDelay - (60f / roundsPerMinute)) * TimeWarp.CurrentRate; + finalFire = false; + } + else + { + finalFire = true; + } + + if (finalFire) + Fire(); + } + + finalFire = false; + } + + yield break; + } + + public Vector3 GetLeadOffset() + { + return fixedLeadOffset; + } + + void RunTrajectorySimulation() + { + //trajectory simulation + if (BDArmorySettings.AIM_ASSIST && BDArmorySettings.DRAW_AIMERS + && (BDArmorySettings.DRAW_DEBUG_LINES + || (vessel && vessel.isActiveVessel && !aiControlled && !MapView.MapIsEnabled && !pointingAtSelf))) + { + Transform fireTransform = fireTransforms[0]; + + if (eWeaponType == WeaponTypes.Laser) + { + Ray ray = new Ray(fireTransform.position, fireTransform.forward); + RaycastHit rayHit; + if (Physics.Raycast(ray, out rayHit, maxTargetingRange, 9076737)) + { + bulletPrediction = rayHit.point; + } + else + { + bulletPrediction = ray.GetPoint(maxTargetingRange); + } + + pointingAtPosition = ray.GetPoint(maxTargetingRange); + } + else //ballistic/cannon weapons + { + float simDeltaTime = 0.155f; + + Vector3 simVelocity = part.rb.velocity + Krakensbane.GetFrameVelocityV3f() + (bulletVelocity * fireTransform.forward); + Vector3 simCurrPos = fireTransform.position + ((part.rb.velocity + Krakensbane.GetFrameVelocityV3f()) * Time.fixedDeltaTime); + Vector3 simPrevPos = simCurrPos; + Vector3 simStartPos = simCurrPos; + bool simulating = true; + + List pointPositions = new List(); + pointPositions.Add(simCurrPos); + + while (simulating) + { + RaycastHit hit; + if (bulletDrop) simVelocity += FlightGlobals.getGeeForceAtPosition(simCurrPos) * simDeltaTime; + simCurrPos += simVelocity * simDeltaTime; + pointPositions.Add(simCurrPos); + + if (Physics.Raycast(simPrevPos, simCurrPos - simPrevPos, out hit, + Vector3.Distance(simPrevPos, simCurrPos), 9076737)) + { + Vessel hitVessel = null; + try + { + KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards(); + hitVessel = (eva ? eva.part : hit.collider.gameObject.GetComponentInParent()).vessel; + } + catch (NullReferenceException) + { + } + + if (hitVessel == null || (hitVessel != null && hitVessel != vessel)) + { + bulletPrediction = hit.point; + simulating = false; + } + } + + simPrevPos = simCurrPos; + + if (visualTargetVessel != null && visualTargetVessel.loaded && !visualTargetVessel.Landed && + (simStartPos - simCurrPos).sqrMagnitude > targetDistance * targetDistance) + { + bulletPrediction = simStartPos + (simCurrPos - simStartPos).normalized * targetDistance; + simulating = false; + } + + if ((simStartPos - simCurrPos).sqrMagnitude > maxTargetingRange * maxTargetingRange) + { + bulletPrediction = simStartPos + ((simCurrPos - simStartPos).normalized * maxTargetingRange); + simulating = false; + } + } + + if (BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) + { + Vector3[] pointsArray = pointPositions.ToArray(); + if (gameObject.GetComponent() == null) + { + LineRenderer lr = gameObject.AddComponent(); + lr.startWidth = .1f; + lr.endWidth = .1f; + lr.positionCount = pointsArray.Length; + for (int i = 0; i < pointsArray.Length; i++) + { + lr.SetPosition(i, pointsArray[i]); + } + } + else + { + LineRenderer lr = gameObject.GetComponent(); + lr.enabled = true; + lr.positionCount = pointsArray.Length; + for (int i = 0; i < pointsArray.Length; i++) + { + lr.SetPosition(i, pointsArray[i]); + } + } + } + } + } + } + + void DrawAlignmentIndicator() + { + if (fireTransforms == null || fireTransforms[0] == null) return; + + Transform refTransform = EditorLogic.RootPart.GetReferenceTransform(); + + if (!refTransform) return; + + Vector3 fwdPos = fireTransforms[0].position + (5 * fireTransforms[0].forward); + BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position, fwdPos, 4, Color.green); + + Vector3 referenceDirection = refTransform.up; + Vector3 refUp = -refTransform.forward; + Vector3 refRight = refTransform.right; + + Vector3 refFwdPos = fireTransforms[0].position + (5 * referenceDirection); + BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position, refFwdPos, 2, Color.white); + + BDGUIUtils.DrawLineBetweenWorldPositions(fwdPos, refFwdPos, 2, XKCDColors.Orange); + + Vector2 guiPos; + if (BDGUIUtils.WorldToGUIPos(fwdPos, out guiPos)) + { + Rect angleRect = new Rect(guiPos.x, guiPos.y, 100, 200); + + Vector3 pitchVector = (5 * Vector3.ProjectOnPlane(fireTransforms[0].forward, refRight)); + Vector3 yawVector = (5 * Vector3.ProjectOnPlane(fireTransforms[0].forward, refUp)); + + BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position + pitchVector, fwdPos, 3, + Color.white); + BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position + yawVector, fwdPos, 3, Color.white); + + float pitch = Vector3.Angle(pitchVector, referenceDirection); + float yaw = Vector3.Angle(yawVector, referenceDirection); + + string convergeDistance; + + Vector3 projAxis = Vector3.Project(refTransform.position - fireTransforms[0].transform.position, + refRight); + float xDist = projAxis.magnitude; + float convergeAngle = 90 - Vector3.Angle(yawVector, refTransform.up); + if (Vector3.Dot(fireTransforms[0].forward, projAxis) > 0) + { + convergeDistance = "Converge: " + + Mathf.Round((xDist * Mathf.Tan(convergeAngle * Mathf.Deg2Rad))).ToString() + "m"; + } + else + { + convergeDistance = "Diverging"; + } + + string xAngle = "X: " + Vector3.Angle(fireTransforms[0].forward, pitchVector).ToString("0.00"); + string yAngle = "Y: " + Vector3.Angle(fireTransforms[0].forward, yawVector).ToString("0.00"); + + GUI.Label(angleRect, xAngle + "\n" + yAngle + "\n" + convergeDistance); + } + } + + #endregion Targeting + + #region Updates + + void UpdateHeat() + { + heat = Mathf.Clamp(heat - heatLoss * TimeWarp.fixedDeltaTime, 0, Mathf.Infinity); + if (heat > maxHeat && !isOverheated) + { + isOverheated = true; + autoFire = false; + audioSource.Stop(); + wasFiring = false; + audioSource2.PlayOneShot(overheatSound); + weaponManager.ResetGuardInterval(); + } + if (heat < maxHeat / 3 && isOverheated) //reset on cooldown + { + isOverheated = false; + } + } + + void UpdateTargetVessel() + { + targetAcquired = false; + slaved = false; + bool atprWasAcquired = atprAcquired; + atprAcquired = false; + + if (weaponManager) + { + //legacy or visual range guard targeting + if (aiControlled && weaponManager && visualTargetVessel && + (visualTargetVessel.transform.position - transform.position).sqrMagnitude < weaponManager.guardRange * weaponManager.guardRange) + { + targetPosition = visualTargetVessel.CoM; + targetVelocity = visualTargetVessel.rb_velocity; + targetAcquired = true; + return; + } + + if (weaponManager.slavingTurrets && turret) + { + slaved = true; + targetPosition = weaponManager.slavedPosition; + targetVelocity = weaponManager.slavedTarget.vessel?.rb_velocity ?? (weaponManager.slavedVelocity - Krakensbane.GetFrameVelocityV3f()); + targetAcquired = true; + return; + } + + if (weaponManager.vesselRadarData && weaponManager.vesselRadarData.locked) + { + TargetSignatureData targetData = weaponManager.vesselRadarData.lockedTargetData.targetData; + targetVelocity = targetData.velocity - Krakensbane.GetFrameVelocityV3f(); + targetPosition = targetData.predictedPosition; + targetAcceleration = targetData.acceleration; + if (targetData.vessel) + { + targetVelocity = targetData.vessel?.rb_velocity ?? targetVelocity; + targetPosition = targetData.vessel.CoM; + } + targetAcquired = true; + return; + } + + //auto proxy tracking + if (vessel.isActiveVessel && autoProxyTrackRange > 0) + { + if (aptrTicker < 20) + { + aptrTicker++; + + if (atprWasAcquired) + { + targetAcquired = true; + atprAcquired = true; + } + } + else + { + aptrTicker = 0; + Vessel tgt = null; + float closestSqrDist = autoProxyTrackRange * autoProxyTrackRange; + List.Enumerator v = BDATargetManager.LoadedVessels.GetEnumerator(); + while (v.MoveNext()) + { + if (v.Current == null || !v.Current.loaded) continue; + if (!v.Current.IsControllable) continue; + if (v.Current == vessel) continue; + Vector3 targetVector = v.Current.transform.position - part.transform.position; + if (Vector3.Dot(targetVector, fireTransforms[0].forward) < 0) continue; + float sqrDist = (v.Current.transform.position - part.transform.position).sqrMagnitude; + if (sqrDist > closestSqrDist) continue; + if (Vector3.Angle(targetVector, fireTransforms[0].forward) > 20) continue; + tgt = v.Current; + closestSqrDist = sqrDist; + } + v.Dispose(); + + if (tgt == null) return; + targetAcquired = true; + atprAcquired = true; + targetPosition = tgt.CoM; + targetVelocity = tgt.rb_velocity; + } + } + } + } + + /// + /// Update target acceleration based on previous velocity. + /// Position is used to clamp acceleration for splashed targets, as ksp produces excessive bobbing. + /// + void updateAcceleration(Vector3 target_rb_velocity, Vector3 position) + { + targetAccelerationPrevious = targetAcceleration; + targetAcceleration = (target_rb_velocity - Krakensbane.GetLastCorrection() - targetVelocityPrevious) / Time.fixedDeltaTime; + float altitude = (float)FlightGlobals.currentMainBody.GetAltitude(position); + if (altitude < 12 && altitude > -10) + targetAcceleration = Vector3.ProjectOnPlane(targetAcceleration, VectorUtils.GetUpDirection(position)); + targetVelocityPrevious = target_rb_velocity; + } + + void UpdateGUIWeaponState() + { + guiStatusString = weaponState.ToString(); + } + + IEnumerator StartupRoutine() + { + weaponState = WeaponStates.PoweringUp; + UpdateGUIWeaponState(); + + if (hasDeployAnim && deployState) + { + deployState.enabled = true; + deployState.speed = 1; + while (deployState.normalizedTime < 1) //wait for animation here + { + yield return null; + } + deployState.normalizedTime = 1; + deployState.speed = 0; + deployState.enabled = false; + } + + weaponState = WeaponStates.Enabled; + UpdateGUIWeaponState(); + BDArmorySetup.Instance.UpdateCursorState(); + } + + IEnumerator ShutdownRoutine() + { + weaponState = WeaponStates.PoweringDown; + UpdateGUIWeaponState(); + BDArmorySetup.Instance.UpdateCursorState(); + if (turret) + { + yield return new WaitForSeconds(0.2f); + + while (!turret.ReturnTurret()) //wait till turret has returned + { + yield return new WaitForFixedUpdate(); + } + } + + if (hasDeployAnim) + { + deployState.enabled = true; + deployState.speed = -1; + while (deployState.normalizedTime > 0) + { + yield return null; + } + deployState.normalizedTime = 0; + deployState.speed = 0; + deployState.enabled = false; + } + + weaponState = WeaponStates.Disabled; + UpdateGUIWeaponState(); + } + + void StopShutdownStartupRoutines() + { + if (shutdownRoutine != null) + { + StopCoroutine(shutdownRoutine); + shutdownRoutine = null; + } + + if (startupRoutine != null) + { + StopCoroutine(startupRoutine); + startupRoutine = null; + } + } + + #endregion Updates + + #region Bullets + + void ParseBulletDragType() + { + bulletDragTypeName = bulletDragTypeName.ToLower(); + + switch (bulletDragTypeName) + { + case "none": + bulletDragType = BulletDragTypes.None; + break; + + case "numericalintegration": + bulletDragType = BulletDragTypes.NumericalIntegration; + break; + + case "analyticestimate": + bulletDragType = BulletDragTypes.AnalyticEstimate; + break; + } + } + + void SetupBulletPool() + { + GameObject templateBullet = new GameObject("Bullet"); + templateBullet.AddComponent(); + templateBullet.SetActive(false); + bulletPool = ObjectPool.CreateObjectPool(templateBullet, 100, true, true); + } + + void SetupShellPool() + { + GameObject templateShell = + (GameObject)Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/shell/model")); + templateShell.SetActive(false); + templateShell.AddComponent(); + shellPool = ObjectPool.CreateObjectPool(templateShell, 50, true, true); + } + + void SetupBullet() + { + bulletInfo = BulletInfo.bullets[bulletType]; + if (bulletType != "def") + { + //use values from bullets.cfg if not the Part Module defaults are used + caliber = bulletInfo.caliber; + bulletVelocity = bulletInfo.bulletVelocity; + bulletMass = bulletInfo.bulletMass; + bulletDragTypeName = bulletInfo.bulletDragTypeName; + cannonShellHeat = bulletInfo.blastHeat; + cannonShellPower = bulletInfo.blastPower; + cannonShellRadius = bulletInfo.blastRadius; + } + ParseBulletDragType(); + } + + protected void SetInitialDetonationDistance() + { + if (this.detonationRange == -1) + { + if (eWeaponType == WeaponTypes.Ballistic && (bulletInfo.tntMass != 0 && (proximityDetonation || airDetonation))) + { + detonationRange = (BlastPhysicsUtils.CalculateBlastRange(bulletInfo.tntMass) * 0.66f); + } + else + { + detonationRange = 0f; + proximityDetonation = false; + } + } + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: DetonationDistance = : " + detonationRange); + } + } + + #endregion Bullets + + #region RMB Info + + public override string GetInfo() + { + BulletInfo binfo = BulletInfo.bullets[bulletType]; + StringBuilder output = new StringBuilder(); + output.Append(Environment.NewLine); + output.AppendLine($"Weapon Type: {weaponType}"); + + if (weaponType == "laser") + { + output.AppendLine($"Laser damage: {laserDamage}"); + } + else + { + output.AppendLine($"Rounds Per Minute: {roundsPerMinute * (fireTransforms?.Length ?? 1)}"); + output.AppendLine($"Ammunition: {ammoName}"); + output.AppendLine($"Bullet type: {bulletType}"); + output.AppendLine($"Bullet mass: {Math.Round(binfo.bulletMass, 2)} kg"); + output.AppendLine($"Muzzle velocity: {Math.Round(binfo.bulletVelocity, 2)} m/s"); + output.AppendLine($"Max Range: {maxEffectiveDistance} m"); + if (weaponType == "cannon" || weaponType == "ballistic") + { + output.AppendLine($"Explosive: {binfo.explosive}"); + if (binfo.explosive) + { + output.AppendLine($"Blast:"); + output.AppendLine($"- tnt mass: {Math.Round((binfo.tntMass > 0 ? binfo.tntMass : binfo.blastPower), 2)} kg"); + output.AppendLine($"- radius: {Math.Round(BlastPhysicsUtils.CalculateBlastRange(binfo.tntMass), 2)} m"); + output.AppendLine($"Air detonation: {airDetonation}"); + if (airDetonation) + { + output.AppendLine($"- auto timing: {airDetonationTiming}"); + output.AppendLine($"- max range: {maxAirDetonationRange} m"); + } + } + } + } + return output.ToString(); + } + + #endregion RMB Info + } + + #region UI //borrowing code from ModularMissile GUI + + [KSPAddon(KSPAddon.Startup.EditorAny, false)] + public class WeaponGroupWindow : MonoBehaviour + { + internal static EventVoid OnActionGroupEditorOpened = new EventVoid("OnActionGroupEditorOpened"); + internal static EventVoid OnActionGroupEditorClosed = new EventVoid("OnActionGroupEditorClosed"); + + private static GUIStyle unchanged; + private static GUIStyle changed; + private static GUIStyle greyed; + private static GUIStyle overfull; + + private static WeaponGroupWindow instance; + private static Vector3 mousePos = Vector3.zero; + + private bool ActionGroupMode; + + private Rect guiWindowRect = new Rect(0, 0, 0, 0); + + private ModuleWeapon WPNmodule; + + [KSPField] public int offsetGUIPos = -1; + + private Vector2 scrollPos; + + [KSPField(isPersistant = false, guiActiveEditor = true, guiActive = false, guiName = "#LOC_BDArmory_ShowGroupEditor"), UI_Toggle(enabledText = "#LOC_BDArmory_ShowGroupEditor_enabledText", disabledText = "#LOC_BDArmory_ShowGroupEditor_disabledText")] [NonSerialized] public bool showRFGUI;//Show Group Editor--close Group GUI--open Group GUI + + private bool styleSetup; + + private string txtName = string.Empty; + + public static void HideGUI() + { + if (instance != null && instance.WPNmodule != null) + { + instance.WPNmodule.WeaponName = instance.WPNmodule.shortName; + instance.WPNmodule = null; + instance.UpdateGUIState(); + } + EditorLogic editor = EditorLogic.fetch; + if (editor != null) + editor.Unlock("BD_MN_GUILock"); + } + + public static void ShowGUI(ModuleWeapon WPNmodule) + { + if (instance != null) + { + instance.WPNmodule = WPNmodule; + instance.UpdateGUIState(); + } + } + + private void UpdateGUIState() + { + enabled = WPNmodule != null; + EditorLogic editor = EditorLogic.fetch; + if (!enabled && editor != null) + editor.Unlock("BD_MN_GUILock"); + } + + private IEnumerator CheckActionGroupEditor() + { + while (EditorLogic.fetch == null) + { + yield return null; + } + EditorLogic editor = EditorLogic.fetch; + while (EditorLogic.fetch != null) + { + if (editor.editorScreen == EditorScreen.Actions) + { + if (!ActionGroupMode) + { + HideGUI(); + OnActionGroupEditorOpened.Fire(); + } + EditorActionGroups age = EditorActionGroups.Instance; + if (WPNmodule && !age.GetSelectedParts().Contains(WPNmodule.part)) + { + HideGUI(); + } + ActionGroupMode = true; + } + else + { + if (ActionGroupMode) + { + HideGUI(); + OnActionGroupEditorClosed.Fire(); + } + ActionGroupMode = false; + } + yield return null; + } + } + + private void Awake() + { + enabled = false; + instance = this; + } + + private void OnDestroy() + { + instance = null; + } + + public void OnGUI() + { + if (!styleSetup) + { + styleSetup = true; + Styles.InitStyles(); + } + + EditorLogic editor = EditorLogic.fetch; + if (!HighLogic.LoadedSceneIsEditor || !editor) + { + return; + } + bool cursorInGUI = false; // nicked the locking code from Ferram + mousePos = Input.mousePosition; //Mouse location; based on Kerbal Engineer Redux code + mousePos.y = Screen.height - mousePos.y; + + int posMult = 0; + if (offsetGUIPos != -1) + { + posMult = offsetGUIPos; + } + if (ActionGroupMode) + { + if (guiWindowRect.width == 0) + { + guiWindowRect = new Rect(430 * posMult, 365, 438, 50); + } + new Rect(guiWindowRect.xMin + 440, mousePos.y - 5, 300, 20); + } + else + { + if (guiWindowRect.width == 0) + { + //guiWindowRect = new Rect(Screen.width - 8 - 430 * (posMult + 1), 365, 438, (Screen.height - 365)); + guiWindowRect = new Rect(Screen.width - 8 - 430 * (posMult + 1), 365, 438, 50); + } + new Rect(guiWindowRect.xMin - (230 - 8), mousePos.y - 5, 220, 20); + } + cursorInGUI = guiWindowRect.Contains(mousePos); + if (cursorInGUI) + { + editor.Lock(false, false, false, "BD_MN_GUILock"); + //if (EditorTooltip.Instance != null) + // EditorTooltip.Instance.HideToolTip(); + } + else + { + editor.Unlock("BD_MN_GUILock"); + } + guiWindowRect = GUILayout.Window(GetInstanceID(), guiWindowRect, GUIWindow, "Weapon Group GUI", Styles.styleEditorPanel); + } + + public void GUIWindow(int windowID) + { + InitializeStyles(); + + GUILayout.BeginVertical(); + GUILayout.Space(20); + + GUILayout.BeginHorizontal(); + + GUILayout.Label("Add to Weapon Group: "); + + txtName = GUILayout.TextField(txtName); + + if (GUILayout.Button("Save & Close")) + { + string newName = string.IsNullOrEmpty(txtName.Trim()) ? WPNmodule.OriginalShortName : txtName.Trim(); + + WPNmodule.WeaponName = newName; + WPNmodule.shortName = newName; + instance.WPNmodule.HideUI(); + } + + GUILayout.EndHorizontal(); + + scrollPos = GUILayout.BeginScrollView(scrollPos); + + GUILayout.EndScrollView(); + + GUILayout.EndVertical(); + + GUI.DragWindow(); + BDGUIUtils.RepositionWindow(ref guiWindowRect); + } + + private static void InitializeStyles() + { + if (unchanged == null) + { + if (GUI.skin == null) + { + unchanged = new GUIStyle(); + changed = new GUIStyle(); + greyed = new GUIStyle(); + overfull = new GUIStyle(); + } + else + { + unchanged = new GUIStyle(GUI.skin.textField); + changed = new GUIStyle(GUI.skin.textField); + greyed = new GUIStyle(GUI.skin.textField); + overfull = new GUIStyle(GUI.skin.label); + } + + unchanged.normal.textColor = Color.white; + unchanged.active.textColor = Color.white; + unchanged.focused.textColor = Color.white; + unchanged.hover.textColor = Color.white; + + changed.normal.textColor = Color.yellow; + changed.active.textColor = Color.yellow; + changed.focused.textColor = Color.yellow; + changed.hover.textColor = Color.yellow; + + greyed.normal.textColor = Color.gray; + + overfull.normal.textColor = Color.red; + } + } + } + + #endregion UI //borrowing code from ModularMissile GUI +} diff --git a/BDArmory/Modules/ModuleWingCommander.cs b/BDArmory/Modules/ModuleWingCommander.cs new file mode 100644 index 000000000..45afe714e --- /dev/null +++ b/BDArmory/Modules/ModuleWingCommander.cs @@ -0,0 +1,645 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using BDArmory.Control; +using BDArmory.Misc; +using BDArmory.Parts; +using BDArmory.UI; +using UniLinq; +using UnityEngine; +using KSP.Localization; + +namespace BDArmory.Modules +{ + public class ModuleWingCommander : PartModule + { + public MissileFire weaponManager; + + List friendlies; + + List wingmen; + [KSPField(isPersistant = true)] public string savedWingmen = string.Empty; + + //[KSPField(guiActive = false, guiActiveEditor = false, guiName = "")] + public string guiTitle = "WingCommander:"; + + [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_WingCommander_Guiname1"), UI_FloatRange(minValue = 20f, maxValue = 200f, stepIncrement = 1, scene = UI_Scene.Editor)]//Formation Spread + public float spread = 100; + + [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "#LOC_BDArmory_WingCommander_Guiname2"), UI_FloatRange(minValue = 0f, maxValue = 100f, stepIncrement = 1, scene = UI_Scene.Editor)]//Formation Lag + public float lag = 7; + + [KSPField(isPersistant = true)] public bool commandSelf; + + List commandedPositions; + bool drawMouseDiamond; + + ScreenMessage screenMessage; + + //int focusIndex = 0; + List focusIndexes; + + [KSPEvent(guiActive = true, guiName = "#LOC_BDArmory_WingCommander_Guiname3")]//ToggleGUI + public void ToggleGUI() + { + showGUI = !showGUI; + if (!showGUI) return; + RefreshFriendlies(); + + //TEMPORARY + wingmen = new List(); + List.Enumerator ps = friendlies.GetEnumerator(); + while (ps.MoveNext()) + { + if (ps.Current == null) continue; + wingmen.Add(ps.Current); + } + ps.Dispose(); + } + + public override void OnStart(StartState state) + { + base.OnStart(state); + + if (HighLogic.LoadedSceneIsFlight) + { + focusIndexes = new List(); + commandedPositions = new List(); + part.force_activate(); + + StartCoroutine(StartupRoutine()); + + GameEvents.onGameStateSave.Add(SaveWingmen); + GameEvents.onVesselLoaded.Add(OnVesselLoad); + GameEvents.onVesselDestroy.Add(OnVesselLoad); + GameEvents.onVesselGoOnRails.Add(OnVesselLoad); + MissileFire.OnChangeTeam += OnToggleTeam; + + screenMessage = new ScreenMessage("", 2, ScreenMessageStyle.LOWER_CENTER); + } + } + + void OnToggleTeam(MissileFire mf, BDTeam team) + { + RefreshFriendlies(); + RefreshWingmen(); + } + + IEnumerator StartupRoutine() + { + while (vessel.packed) + { + yield return null; + } + + weaponManager = part.FindModuleImplementing(); + + RefreshFriendlies(); + RefreshWingmen(); + LoadWingmen(); + } + + void OnDestroy() + { + if (HighLogic.LoadedSceneIsFlight) + { + GameEvents.onGameStateSave.Remove(SaveWingmen); + GameEvents.onVesselLoaded.Remove(OnVesselLoad); + GameEvents.onVesselDestroy.Remove(OnVesselLoad); + GameEvents.onVesselGoOnRails.Remove(OnVesselLoad); + MissileFire.OnChangeTeam -= OnToggleTeam; + } + } + + void OnVesselLoad(Vessel v) + { + if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed) + { + RefreshFriendlies(); + RefreshWingmen(); + } + } + + void RefreshFriendlies() + { + if (!weaponManager) return; + friendlies = new List(); + List.Enumerator vs = BDATargetManager.LoadedVessels.GetEnumerator(); + while (vs.MoveNext()) + { + if (vs.Current == null) continue; + if (!vs.Current.loaded || vs.Current == vessel) continue; + + IBDAIControl pilot = null; + MissileFire wm = null; + List.Enumerator ps = vs.Current.FindPartModulesImplementing().GetEnumerator(); + while (ps.MoveNext()) + { + if (ps.Current == null) continue; + pilot = ps.Current; + break; + } + ps.Dispose(); + + if (pilot == null) continue; + List.Enumerator ws = vs.Current.FindPartModulesImplementing().GetEnumerator(); + while (ws.MoveNext()) + { + // TODO: JDK: note that this assigns the last module found. Is that what we want? + wm = ws.Current; + } + ws.Dispose(); + + if (!wm || wm.Team != weaponManager.Team) continue; + friendlies.Add(pilot); + } + vs.Dispose(); + + //TEMPORARY + wingmen = new List(); + List.Enumerator fs = friendlies.GetEnumerator(); + while (fs.MoveNext()) + { + if (fs.Current == null) continue; + wingmen.Add(fs.Current); + } + fs.Dispose(); + } + + void RefreshWingmen() + { + if (wingmen == null) + { + wingmen = new List(); + //focusIndex = 0; + focusIndexes.Clear(); + return; + } + wingmen.RemoveAll(w => w == null || (w.weaponManager && w.weaponManager.Team != weaponManager.Team)); + + List uniqueIndexes = new List(); + List.Enumerator fIndexes = focusIndexes.GetEnumerator(); + while (fIndexes.MoveNext()) + { + int clampedIndex = Mathf.Clamp(fIndexes.Current, 0, wingmen.Count - 1); + if (!uniqueIndexes.Contains(clampedIndex)) + { + uniqueIndexes.Add(clampedIndex); + } + } + fIndexes.Dispose(); + focusIndexes = new List(uniqueIndexes); + } + + void SaveWingmen(ConfigNode cfg) + { + if (wingmen == null) + { + return; + } + + savedWingmen = string.Empty; + List.Enumerator pilots = wingmen.GetEnumerator(); + while (pilots.MoveNext()) + { + if (pilots.Current == null) continue; + savedWingmen += pilots.Current.vessel.id + ","; + } + pilots.Dispose(); + } + + void LoadWingmen() + { + wingmen = new List(); + + if (savedWingmen == string.Empty) return; + IEnumerator wingIDs = savedWingmen.Split(new char[] { ',' }).AsEnumerable().GetEnumerator(); + while (wingIDs.MoveNext()) + { + List.Enumerator vs = BDATargetManager.LoadedVessels.GetEnumerator(); + while (vs.MoveNext()) + { + if (vs.Current == null) continue; + if (!vs.Current.loaded) continue; + + if (vs.Current.id.ToString() != wingIDs.Current) continue; + List.Enumerator pilots = vs.Current.FindPartModulesImplementing().GetEnumerator(); + while (pilots.MoveNext()) + { + if (pilots.Current == null) continue; + wingmen.Add(pilots.Current); + break; + } + pilots.Dispose(); + } + vs.Dispose(); + } + wingIDs.Dispose(); + } + + public bool showGUI; + bool rectInit; + float buttonStartY = 30; + float buttonHeight = 24; + float buttonGap = 3; + float margin = 6; + private float windowWidth = 240; + private float windowHeight = 100; + float buttonWidth; + float buttonEndY; + GUIStyle wingmanButtonStyle; + GUIStyle wingmanButtonSelectedStyle; + + void OnGUI() + { + if (!HighLogic.LoadedSceneIsFlight || !vessel || !vessel.isActiveVessel || vessel.packed) return; + if (!BDArmorySetup.GAME_UI_ENABLED) return; + if (showGUI) + { + if (!rectInit) + { + // this Rect initialization ensures any save issues with height or width of the window are resolved + BDArmorySetup.WindowRectWingCommander = new Rect(BDArmorySetup.WindowRectWingCommander.x, BDArmorySetup.WindowRectWingCommander.y, windowWidth, windowHeight); + buttonWidth = BDArmorySetup.WindowRectWingCommander.width - (2 * margin); + buttonEndY = buttonStartY; + wingmanButtonStyle = new GUIStyle(BDArmorySetup.BDGuiSkin.button); + wingmanButtonStyle.alignment = TextAnchor.MiddleLeft; + wingmanButtonStyle.wordWrap = false; + wingmanButtonStyle.fontSize = 11; + wingmanButtonSelectedStyle = new GUIStyle(BDArmorySetup.BDGuiSkin.box); + wingmanButtonSelectedStyle.alignment = TextAnchor.MiddleLeft; + wingmanButtonSelectedStyle.wordWrap = false; + wingmanButtonSelectedStyle.fontSize = 11; + rectInit = true; + } + // this Rect initialization ensures any save issues with height or width of the window are resolved + //BDArmorySetup.WindowRectWingCommander = new Rect(BDArmorySetup.WindowRectWingCommander.x, BDArmorySetup.WindowRectWingCommander.y, windowWidth, windowHeight); + BDArmorySetup.WindowRectWingCommander = GUI.Window(1293293, BDArmorySetup.WindowRectWingCommander, WingmenWindow, Localizer.Format("#LOC_BDArmory_WingCommander_Title"),//"WingCommander" + BDArmorySetup.BDGuiSkin.window); + + if (showAGWindow) AGWindow(); + } + + //command position diamonds + float diamondSize = 24; + List.Enumerator comPos = commandedPositions.GetEnumerator(); + while (comPos.MoveNext()) + { + BDGUIUtils.DrawTextureOnWorldPos(comPos.Current.worldPos, BDArmorySetup.Instance.greenDiamondTexture, + new Vector2(diamondSize, diamondSize), 0); + Vector2 labelPos; + if (!BDGUIUtils.WorldToGUIPos(comPos.Current.worldPos, out labelPos)) continue; + labelPos.x += diamondSize / 2; + labelPos.y -= 10; + GUI.Label(new Rect(labelPos.x, labelPos.y, 300, 20), comPos.Current.name); + } + comPos.Dispose(); + + if (!drawMouseDiamond) return; + Vector2 mouseDiamondPos = Input.mousePosition; + Rect mouseDiamondRect = new Rect(mouseDiamondPos.x - (diamondSize / 2), + Screen.height - mouseDiamondPos.y - (diamondSize / 2), diamondSize, diamondSize); + GUI.DrawTexture(mouseDiamondRect, BDArmorySetup.Instance.greenDiamondTexture, + ScaleMode.StretchToFill, true); + } + + delegate void CommandFunction(IBDAIControl wingman, int index, object data); + + void WingmenWindow(int windowID) + { + float height = buttonStartY; + GUI.DragWindow(new Rect(0, 0, BDArmorySetup.WindowRectWingCommander.width - buttonStartY - margin - margin, buttonStartY)); + + //close buttton + float xSize = buttonStartY - margin - margin; + if (GUI.Button(new Rect(buttonWidth + (2 * buttonGap) - xSize, margin, xSize, xSize), "X", + BDArmorySetup.BDGuiSkin.button)) + { + showGUI = false; + } + + GUI.Box( + new Rect(margin - buttonGap, buttonStartY - buttonGap, buttonWidth + (2 * buttonGap), + Mathf.Max(wingmen.Count * (buttonHeight + buttonGap), 10)), GUIContent.none, BDArmorySetup.BDGuiSkin.box); + buttonEndY = buttonStartY; + for (int i = 0; i < wingmen.Count; i++) + { + WingmanButton(i, out buttonEndY); + } + buttonEndY = Mathf.Max(buttonEndY, 15f); + height += buttonEndY; + + //command buttons + float commandButtonLine = 0; + CommandButton(SelectAll, Localizer.Format("#LOC_BDArmory_WingCommander_SelectAll"), ref commandButtonLine, false, false);//"Select All" + //commandButtonLine += 0.25f; + + commandSelf = + GUI.Toggle( + new Rect(margin, margin + buttonEndY + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth, + buttonHeight), commandSelf, Localizer.Format("#LOC_BDArmory_WingCommander_CommandSelf"), BDArmorySetup.BDGuiSkin.toggle);//"Command Self" + commandButtonLine++; + + commandButtonLine += 0.10f; + + CommandButton(CommandFollow, Localizer.Format("#LOC_BDArmory_WingCommander_Follow"), ref commandButtonLine, true, false);//"Follow" + CommandButton(CommandFlyTo, Localizer.Format("#LOC_BDArmory_WingCommander_FlyToPos"), ref commandButtonLine, true, waitingForFlytoPos);//"Fly To Pos" + CommandButton(CommandAttack, Localizer.Format("#LOC_BDArmory_WingCommander_AttackPos"), ref commandButtonLine, true, waitingForAttackPos);//"Attack Pos" + CommandButton(OpenAGWindow, Localizer.Format("#LOC_BDArmory_WingCommander_ActionGroup"), ref commandButtonLine, false, showAGWindow);//"Action Group" + CommandButton(CommandTakeOff, Localizer.Format("#LOC_BDArmory_WingCommander_TakeOff"), ref commandButtonLine, true, false);//"Take Off" + commandButtonLine += 0.5f; + CommandButton(CommandRelease, Localizer.Format("#LOC_BDArmory_WingCommander_Release"), ref commandButtonLine, true, false);//"Release" + + commandButtonLine += 0.5f; + GUI.Label( + new Rect(margin, buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth, 20), + Localizer.Format("#LOC_BDArmory_WingCommander_FormationSettings") + ":", BDArmorySetup.BDGuiSkin.label);//Formation Settings + commandButtonLine++; + GUI.Label( + new Rect(margin, buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth / 3, 20), + Localizer.Format("#LOC_BDArmory_WingCommander_Spread") + ": " + spread.ToString("0"), BDArmorySetup.BDGuiSkin.label);//Spread + spread = + GUI.HorizontalSlider( + new Rect(margin + (buttonWidth / 3), + buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), 2 * buttonWidth / 3, 20), + spread, 1f, 200f, BDArmorySetup.BDGuiSkin.horizontalSlider, BDArmorySetup.BDGuiSkin.horizontalSliderThumb); + commandButtonLine++; + GUI.Label( + new Rect(margin, buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth / 3, 20), + Localizer.Format("#LOC_BDArmory_WingCommander_Lag") + ": " + lag.ToString("0"), BDArmorySetup.BDGuiSkin.label);//Lag + lag = + GUI.HorizontalSlider( + new Rect(margin + (buttonWidth / 3), + buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), 2 * buttonWidth / 3, 20), lag, + 0f, 100f, BDArmorySetup.BDGuiSkin.horizontalSlider, BDArmorySetup.BDGuiSkin.horizontalSliderThumb); + commandButtonLine++; + + //resize window + height += ((commandButtonLine - 1) * (buttonHeight + buttonGap)); + BDArmorySetup.WindowRectWingCommander.height = height; + GUI.DragWindow(BDArmorySetup.WindowRectWingCommander); + BDGUIUtils.RepositionWindow(ref BDArmorySetup.WindowRectWingCommander); + } + + void WingmanButton(int index, out float buttonEndY) + { + int i = index; + Rect buttonRect = new Rect(margin, buttonStartY + (i * (buttonHeight + buttonGap)), buttonWidth, buttonHeight); + GUIStyle style = (focusIndexes.Contains(i)) ? wingmanButtonSelectedStyle : wingmanButtonStyle; + string label = " " + wingmen[i].vessel.vesselName + " (" + wingmen[i].currentStatus + ")"; + if (GUI.Button(buttonRect, label, style)) + { + if (focusIndexes.Contains(i)) + { + focusIndexes.Remove(i); + } + else + { + focusIndexes.Add(i); + } + } + buttonEndY = buttonStartY + ((i + 1.5f) * buttonHeight); + } + + void CommandButton(CommandFunction func, string buttonLabel, ref float buttonLine, bool sendToWingmen, + bool pressed, object data = null) + { + CommandButton(func, buttonLabel, ref buttonLine, buttonEndY, margin, buttonGap, buttonWidth, buttonHeight, + sendToWingmen, pressed, data); + } + + void CommandButton(CommandFunction func, string buttonLabel, ref float buttonLine, float startY, float margin, + float buttonGap, float buttonWidth, float buttonHeight, bool sendToWingmen, bool pressed, object data) + { + float yPos = startY + margin + ((buttonHeight + buttonGap) * buttonLine); + if (GUI.Button(new Rect(margin, yPos, buttonWidth, buttonHeight), buttonLabel, + pressed ? BDArmorySetup.BDGuiSkin.box : BDArmorySetup.BDGuiSkin.button)) + { + if (sendToWingmen) + { + if (wingmen.Count > 0) + { + List.Enumerator index = focusIndexes.GetEnumerator(); + while (index.MoveNext()) + { + func(wingmen[index.Current], index.Current, data); + } + index.Dispose(); + } + + if (commandSelf) + { + List.Enumerator ai = vessel.FindPartModulesImplementing().GetEnumerator(); + while (ai.MoveNext()) + { + func(ai.Current, -1, data); + } + ai.Dispose(); + } + } + else + { + func(null, -1, null); + } + } + + buttonLine++; + } + + void CommandRelease(IBDAIControl wingman, int index, object data) + { + wingman.ReleaseCommand(); + } + + void CommandFollow(IBDAIControl wingman, int index, object data) + { + wingman.CommandFollow(this, index); + } + + public void CommandAllFollow() + { + RefreshFriendlies(); + int i = 0; + List.Enumerator wingman = friendlies.GetEnumerator(); + while (wingman.MoveNext()) + { + if (wingman.Current == null) continue; + wingman.Current.CommandFollow(this, i); + i++; + } + wingman.Dispose(); + } + + void CommandAG(IBDAIControl wingman, int index, object ag) + { + //Debug.Log("object to string: "+ag.ToString()); + KSPActionGroup actionGroup = (KSPActionGroup)ag; + //Debug.Log("ag to string: " + actionGroup.ToString()); + wingman.CommandAG(actionGroup); + } + + void CommandTakeOff(IBDAIControl wingman, int index, object data) + { + wingman.CommandTakeOff(); + } + + void OpenAGWindow(IBDAIControl wingman, int index, object data) + { + showAGWindow = !showAGWindow; + } + + public bool showAGWindow; + float agWindowHeight = 10; + public Rect agWindowRect; + + void AGWindow() + { + float width = 100; + float buttonHeight = 20; + float agMargin = 5; + float newHeight = 0; + agWindowRect = new Rect(BDArmorySetup.WindowRectWingCommander.x + BDArmorySetup.WindowRectWingCommander.width, BDArmorySetup.WindowRectWingCommander.y, width, agWindowHeight); + GUI.Box(agWindowRect, string.Empty, BDArmorySetup.BDGuiSkin.window); + GUI.BeginGroup(agWindowRect); + newHeight += agMargin; + GUIStyle titleStyle = new GUIStyle(BDArmorySetup.BDGuiSkin.label); + titleStyle.alignment = TextAnchor.MiddleCenter; + GUI.Label(new Rect(agMargin, 5, width - (2 * agMargin), 20), Localizer.Format("#LOC_BDArmory_WingCommander_ActionGroups"), titleStyle);//"Action Groups" + newHeight += 20; + float startButtonY = newHeight; + float buttonLine = 0; + int i = -1; + IEnumerator ag = Enum.GetValues(typeof(KSPActionGroup)).Cast().GetEnumerator(); + while (ag.MoveNext()) + { + i++; + if (i <= 1) continue; + CommandButton(CommandAG, ag.Current.ToString(), ref buttonLine, startButtonY, agMargin, buttonGap, + width - (2 * agMargin), buttonHeight, true, false, ag.Current); + newHeight += buttonHeight + buttonGap; + } + ag.Dispose(); + newHeight += agMargin; + GUI.EndGroup(); + + agWindowHeight = newHeight; + } + + void SelectAll(IBDAIControl wingman, int index, object data) + { + for (int i = 0; i < wingmen.Count; i++) + { + if (!focusIndexes.Contains(i)) + { + focusIndexes.Add(i); + } + } + } + + void CommandFlyTo(IBDAIControl wingman, int index, object data) + { + StartCoroutine(CommandPosition(wingman, PilotCommands.FlyTo)); + } + + void CommandAttack(IBDAIControl wingman, int index, object data) + { + StartCoroutine(CommandPosition(wingman, PilotCommands.Attack)); + } + + bool waitingForFlytoPos; + bool waitingForAttackPos; + + IEnumerator CommandPosition(IBDAIControl wingman, PilotCommands command) + { + if (focusIndexes.Count == 0 && !commandSelf) + { + yield break; + } + + DisplayScreenMessage(Localizer.Format("#LOC_BDArmory_WingCommander_ScreenMessage"));//"Select target coordinates.\nRight-click to cancel." + + if (command == PilotCommands.FlyTo) + { + waitingForFlytoPos = true; + } + else if (command == PilotCommands.Attack) + { + waitingForAttackPos = true; + } + + yield return null; + + bool waitingForPos = true; + drawMouseDiamond = true; + while (waitingForPos) + { + if (Input.GetMouseButtonDown(1)) + { + break; + } + if (Input.GetMouseButtonDown(0)) + { + Vector3 mousePos = new Vector3(Input.mousePosition.x / Screen.width, + Input.mousePosition.y / Screen.height, 0); + Plane surfPlane = new Plane(vessel.upAxis, + vessel.transform.position - (vessel.altitude * vessel.upAxis)); + Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mousePos); + float dist; + if (surfPlane.Raycast(ray, out dist)) + { + Vector3 worldPoint = ray.GetPoint(dist); + Vector3d gps = VectorUtils.WorldPositionToGeoCoords(worldPoint, vessel.mainBody); + + if (command == PilotCommands.FlyTo) + { + wingman.CommandFlyTo(gps); + } + else if (command == PilotCommands.Attack) + { + wingman.CommandAttack(gps); + } + + StartCoroutine(CommandPositionGUIRoutine(wingman, new GPSTargetInfo(gps, command.ToString()))); + } + + break; + } + yield return null; + } + + waitingForAttackPos = false; + waitingForFlytoPos = false; + drawMouseDiamond = false; + ScreenMessages.RemoveMessage(screenMessage); + } + + IEnumerator CommandPositionGUIRoutine(IBDAIControl wingman, GPSTargetInfo tInfo) + { + //RemoveCommandPos(tInfo); + commandedPositions.Add(tInfo); + yield return new WaitForSeconds(0.25f); + while (Vector3d.Distance(wingman.commandGPS, tInfo.gpsCoordinates) < 0.01f && + (wingman.currentCommand == PilotCommands.Attack || + wingman.currentCommand == PilotCommands.FlyTo)) + { + yield return null; + } + RemoveCommandPos(tInfo); + } + + void RemoveCommandPos(GPSTargetInfo tInfo) + { + commandedPositions.RemoveAll(t => t.EqualsTarget(tInfo)); + } + + void DisplayScreenMessage(string message) + { + if (BDArmorySetup.GAME_UI_ENABLED && vessel == FlightGlobals.ActiveVessel) + { + ScreenMessages.RemoveMessage(screenMessage); + screenMessage.message = message; + ScreenMessages.PostScreenMessage(screenMessage); + } + } + } +} diff --git a/BDArmory/Modules/RadarWarningReceiver.cs b/BDArmory/Modules/RadarWarningReceiver.cs new file mode 100644 index 000000000..de5c7e8bb --- /dev/null +++ b/BDArmory/Modules/RadarWarningReceiver.cs @@ -0,0 +1,475 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Misc; +using BDArmory.Radar; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class RadarWarningReceiver : PartModule + { + public delegate void RadarPing(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime); + + public static event RadarPing OnRadarPing; + + public delegate void MissileLaunchWarning(Vector3 source, Vector3 direction); + + public static event MissileLaunchWarning OnMissileLaunch; + + public enum RWRThreatTypes + { + SAM = 0, + Fighter = 1, + AWACS = 2, + MissileLaunch = 3, + MissileLock = 4, + Detection = 5, + Sonar = 6, + Torpedo = 7, + TorpedoLock = 8 + } + + string[] iconLabels = new string[] { "S", "F", "A", "M", "M", "D", "So", "T", "T" }; + + public MissileFire weaponManager; + + // This field may not need to be persistent. It was combining display with active RWR status. + [KSPField(isPersistant = true)] public bool rwrEnabled; + + // This field was added to separate RWR active status from the display of the RWR. the RWR should be running all the time... + public bool displayRWR = false; + internal static bool resizingWindow = false; + + public Rect RWRresizeRect = new Rect( + BDArmorySetup.WindowRectRwr.width - (16 * BDArmorySettings.RWR_WINDOW_SCALE), + BDArmorySetup.WindowRectRwr.height - (16 * BDArmorySettings.RWR_WINDOW_SCALE), + (16 * BDArmorySettings.RWR_WINDOW_SCALE), + (16 * BDArmorySettings.RWR_WINDOW_SCALE)); + + public static Texture2D rwrDiamondTexture = + GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "rwrDiamond", false); + + public static Texture2D rwrMissileTexture = + GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "rwrMissileIcon", false); + + public static AudioClip radarPingSound; + public static AudioClip missileLockSound; + public static AudioClip missileLaunchSound; + public static AudioClip sonarPing; + public static AudioClip torpedoPing; + private float torpedoPingPitch; + private float audioSourceRepeatDelay; + private const float audioSourceRepeatDelayTime = 0.5f; + + //float lastTimePinged = 0; + const float minPingInterval = 0.12f; + const float pingPersistTime = 1; + + const int dataCount = 10; + + internal float rwrDisplayRange = BDArmorySettings.MAX_ACTIVE_RADAR_RANGE; + internal static float RwrSize = 256; + internal static float BorderSize = 10; + internal static float HeaderSize = 15; + + public TargetSignatureData[] pingsData; + public Vector3[] pingWorldPositions; + List launchWarnings; + + Transform rt; + + Transform referenceTransform + { + get + { + if (!rt) + { + rt = new GameObject().transform; + rt.parent = part.transform; + rt.localPosition = Vector3.zero; + } + return rt; + } + } + + internal static Rect RwrDisplayRect = new Rect(0, 0, RwrSize * BDArmorySettings.RWR_WINDOW_SCALE, RwrSize * BDArmorySettings.RWR_WINDOW_SCALE); + + GUIStyle rwrIconLabelStyle; + + AudioSource audioSource; + public static bool WindowRectRWRInitialized; + + public override void OnAwake() + { + radarPingSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rwrPing"); + missileLockSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rwrMissileLock"); + missileLaunchSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/mLaunchWarning"); + sonarPing = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rwr_sonarping"); + torpedoPing = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rwr_torpedoping"); + } + + public override void OnStart(StartState state) + { + if (HighLogic.LoadedSceneIsFlight) + { + pingsData = new TargetSignatureData[dataCount]; + pingWorldPositions = new Vector3[dataCount]; + TargetSignatureData.ResetTSDArray(ref pingsData); + launchWarnings = new List(); + + rwrIconLabelStyle = new GUIStyle(); + rwrIconLabelStyle.alignment = TextAnchor.MiddleCenter; + rwrIconLabelStyle.normal.textColor = Color.green; + rwrIconLabelStyle.fontSize = 12; + rwrIconLabelStyle.border = new RectOffset(0, 0, 0, 0); + rwrIconLabelStyle.clipping = TextClipping.Overflow; + rwrIconLabelStyle.wordWrap = false; + rwrIconLabelStyle.fontStyle = FontStyle.Bold; + + audioSource = gameObject.AddComponent(); + audioSource.minDistance = 500; + audioSource.maxDistance = 1000; + audioSource.spatialBlend = 1; + audioSource.dopplerLevel = 0; + audioSource.loop = false; + + UpdateVolume(); + BDArmorySetup.OnVolumeChange += UpdateVolume; + + //float size = RwrDisplayRect.height + 20; + if (!WindowRectRWRInitialized) + { + BDArmorySetup.WindowRectRwr = new Rect(40, Screen.height - RwrDisplayRect.height, RwrDisplayRect.height + BorderSize, RwrDisplayRect.height + BorderSize + HeaderSize); + WindowRectRWRInitialized = true; + } + + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + mf.Current.rwr = this; + if (!weaponManager) + { + weaponManager = mf.Current; + } + } + mf.Dispose(); + //if (rwrEnabled) EnableRWR(); + EnableRWR(); + } + } + + void UpdateVolume() + { + if (audioSource) + { + audioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; + } + } + + public void EnableRWR() + { + OnRadarPing += ReceivePing; + OnMissileLaunch += ReceiveLaunchWarning; + rwrEnabled = true; + } + + public void DisableRWR() + { + OnRadarPing -= ReceivePing; + OnMissileLaunch -= ReceiveLaunchWarning; + rwrEnabled = false; + } + + void OnDestroy() + { + OnRadarPing -= ReceivePing; + OnMissileLaunch -= ReceiveLaunchWarning; + BDArmorySetup.OnVolumeChange -= UpdateVolume; + } + + IEnumerator PingLifeRoutine(int index, float lifeTime) + { + yield return new WaitForSeconds(Mathf.Clamp(lifeTime - 0.04f, minPingInterval, lifeTime)); + pingsData[index] = TargetSignatureData.noTarget; + } + + IEnumerator LaunchWarningRoutine(TargetSignatureData data) + { + launchWarnings.Add(data); + yield return new WaitForSeconds(2); + launchWarnings.Remove(data); + } + + void ReceiveLaunchWarning(Vector3 source, Vector3 direction) + { + if (referenceTransform == null) return; + if (part == null) return; + if (weaponManager == null) return; + + float sqrDist = (part.transform.position - source).sqrMagnitude; + if (sqrDist < Mathf.Pow(BDArmorySettings.MAX_ENGAGEMENT_RANGE, 2) && sqrDist > Mathf.Pow(100, 2) && + Vector3.Angle(direction, part.transform.position - source) < 15) + { + StartCoroutine( + LaunchWarningRoutine(new TargetSignatureData(Vector3.zero, + RadarUtils.WorldToRadar(source, referenceTransform, RwrDisplayRect, rwrDisplayRange), Vector3.zero, + true, (float)RWRThreatTypes.MissileLaunch))); + PlayWarningSound(RWRThreatTypes.MissileLaunch); + + if (weaponManager && weaponManager.guardMode) + { + weaponManager.FireAllCountermeasures(Random.Range(2, 4)); + weaponManager.incomingThreatPosition = source; + } + } + } + + void ReceivePing(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime) + { + if (v == null) return; + if (referenceTransform == null) return; + if (weaponManager == null) return; + + if (rwrEnabled && vessel && v == vessel) + { + //if we are airborne or on land, no Sonar or SLW type weapons on the RWR! + if ((type == RWRThreatTypes.Torpedo || type == RWRThreatTypes.TorpedoLock || type == RWRThreatTypes.Sonar) && (vessel.situation != Vessel.Situations.SPLASHED)) + { + // rwr stays silent... + return; + } + + if (type == RWRThreatTypes.MissileLaunch || type == RWRThreatTypes.Torpedo) + { + StartCoroutine( + LaunchWarningRoutine(new TargetSignatureData(Vector3.zero, + RadarUtils.WorldToRadar(source, referenceTransform, RwrDisplayRect, rwrDisplayRange), + Vector3.zero, true, (float)type))); + PlayWarningSound(type, (source - vessel.transform.position).sqrMagnitude); + return; + } + else if (type == RWRThreatTypes.MissileLock) + { + if (weaponManager && weaponManager.guardMode) + { + weaponManager.FireChaff(); + // TODO: if torpedo inbound, also fire accoustic decoys (not yet implemented...) + } + } + + int openIndex = -1; + for (int i = 0; i < dataCount; i++) + { + if (pingsData[i].exists && + ((Vector2)pingsData[i].position - + RadarUtils.WorldToRadar(source, referenceTransform, RwrDisplayRect, rwrDisplayRange)).sqrMagnitude < 900f) //prevent ping spam + { + break; + } + + if (!pingsData[i].exists && openIndex == -1) + { + openIndex = i; + } + } + + if (openIndex >= 0) + { + referenceTransform.rotation = Quaternion.LookRotation(vessel.ReferenceTransform.up, + VectorUtils.GetUpDirection(transform.position)); + + pingsData[openIndex] = new TargetSignatureData(Vector3.zero, + RadarUtils.WorldToRadar(source, referenceTransform, RwrDisplayRect, rwrDisplayRange), Vector3.zero, + true, (float)type); // HACK! Evil misuse of signalstrength for the threat type! + pingWorldPositions[openIndex] = source; + StartCoroutine(PingLifeRoutine(openIndex, persistTime)); + + PlayWarningSound(type, (source - vessel.transform.position).sqrMagnitude); + } + } + } + + void PlayWarningSound(RWRThreatTypes type, float sqrDistance = 0f) + { + if (vessel.isActiveVessel && audioSourceRepeatDelay <= 0f) + { + switch (type) + { + case RWRThreatTypes.MissileLaunch: + if (audioSource.isPlaying) + break; + audioSource.clip = missileLaunchSound; + audioSource.Play(); + break; + + case RWRThreatTypes.Sonar: + if (audioSource.isPlaying) + break; + audioSource.clip = sonarPing; + audioSource.Play(); + break; + + case RWRThreatTypes.Torpedo: + case RWRThreatTypes.TorpedoLock: + if (audioSource.isPlaying) + break; + torpedoPingPitch = Mathf.Lerp(1.5f, 1.0f, sqrDistance / (2000 * 2000)); //within 2km increase ping pitch + audioSource.Stop(); + audioSource.clip = torpedoPing; + audioSource.pitch = torpedoPingPitch; + audioSource.Play(); + audioSourceRepeatDelay = audioSourceRepeatDelayTime; //set a min repeat delay to prevent too much audi pinging + break; + + case RWRThreatTypes.MissileLock: + if (audioSource.isPlaying) + break; + audioSource.clip = (missileLockSound); + audioSource.Play(); + audioSourceRepeatDelay = audioSourceRepeatDelayTime; //set a min repeat delay to prevent too much audi pinging + break; + + default: + if (!audioSource.isPlaying) + { + audioSource.clip = (radarPingSound); + audioSource.Play(); + audioSourceRepeatDelay = audioSourceRepeatDelayTime; //set a min repeat delay to prevent too much audi pinging + } + break; + } + } + } + + void OnGUI() + { + if (!HighLogic.LoadedSceneIsFlight || !FlightGlobals.ready || !BDArmorySetup.GAME_UI_ENABLED || + !vessel.isActiveVessel || !displayRWR) return; + if (audioSourceRepeatDelay > 0) + audioSourceRepeatDelay -= Time.fixedDeltaTime; + + if (Event.current.type == EventType.MouseUp && resizingWindow) + { + resizingWindow = false; + } + + BDArmorySetup.WindowRectRwr = GUI.Window(94353, BDArmorySetup.WindowRectRwr, WindowRwr, + "Radar Warning Receiver", GUI.skin.window); + BDGUIUtils.UseMouseEventInRect(RwrDisplayRect); + } + + internal void WindowRwr(int windowID) + { + GUI.DragWindow(new Rect(0, 0, BDArmorySetup.WindowRectRwr.width - 18, 30)); + if (GUI.Button(new Rect(BDArmorySetup.WindowRectRwr.width - 18, 2, 16, 16), "X", GUI.skin.button)) + { + displayRWR = false; + } + GUI.BeginGroup(new Rect(BorderSize / 2, HeaderSize + (BorderSize / 2), RwrDisplayRect.width, RwrDisplayRect.height)); + //GUI.DragWindow(RwrDisplayRect); + + GUI.DrawTexture(RwrDisplayRect, VesselRadarData.omniBgTexture, ScaleMode.StretchToFill, false); + float pingSize = 32 * BDArmorySettings.RWR_WINDOW_SCALE; + + for (int i = 0; i < dataCount; i++) + { + Vector2 pingPosition = (Vector2)pingsData[i].position; + //pingPosition = Vector2.MoveTowards(displayRect.center, pingPosition, displayRect.center.x - (pingSize/2)); + Rect pingRect = new Rect(pingPosition.x - (pingSize / 2), pingPosition.y - (pingSize / 2), pingSize, + pingSize); + + if (!pingsData[i].exists) continue; + if (pingsData[i].signalStrength == (float)RWRThreatTypes.MissileLock) //Hack! Evil misuse of field signalstrength... + { + GUI.DrawTexture(pingRect, rwrMissileTexture, ScaleMode.StretchToFill, true); + } + else + { + GUI.DrawTexture(pingRect, rwrDiamondTexture, ScaleMode.StretchToFill, true); + GUI.Label(pingRect, iconLabels[Mathf.RoundToInt(pingsData[i].signalStrength)], rwrIconLabelStyle); //Hack! Evil misuse of field signalstrength... + } + } + + List.Enumerator lw = launchWarnings.GetEnumerator(); + while (lw.MoveNext()) + { + Vector2 pingPosition = (Vector2)lw.Current.position; + //pingPosition = Vector2.MoveTowards(displayRect.center, pingPosition, displayRect.center.x - (pingSize/2)); + + Rect pingRect = new Rect(pingPosition.x - (pingSize / 2), pingPosition.y - (pingSize / 2), pingSize, + pingSize); + GUI.DrawTexture(pingRect, rwrMissileTexture, ScaleMode.StretchToFill, true); + } + lw.Dispose(); + GUI.EndGroup(); + + // Resizing code block. + RWRresizeRect = + new Rect(BDArmorySetup.WindowRectRwr.width - 18, BDArmorySetup.WindowRectRwr.height - 18, 16, 16); + GUI.DrawTexture(RWRresizeRect, Misc.Misc.resizeTexture, ScaleMode.StretchToFill, true); + if (Event.current.type == EventType.MouseDown && RWRresizeRect.Contains(Event.current.mousePosition)) + { + resizingWindow = true; + } + + if (Event.current.type == EventType.Repaint && resizingWindow) + { + if (Mouse.delta.x != 0 || Mouse.delta.y != 0) + { + float diff = Mouse.delta.x + Mouse.delta.y; + UpdateRWRScale(diff); + BDArmorySetup.ResizeRwrWindow(BDArmorySettings.RWR_WINDOW_SCALE); + } + } + // End Resizing code. + + BDGUIUtils.RepositionWindow(ref BDArmorySetup.WindowRectRwr); + } + + internal static void UpdateRWRScale(float diff) + { + float scaleDiff = ((diff / (BDArmorySetup.WindowRectRwr.width + BDArmorySetup.WindowRectRwr.height)) * 100 * .01f); + BDArmorySettings.RWR_WINDOW_SCALE += Mathf.Abs(scaleDiff) > .01f ? scaleDiff : scaleDiff > 0 ? .01f : -.01f; + BDArmorySettings.RWR_WINDOW_SCALE = + BDArmorySettings.RWR_WINDOW_SCALE > BDArmorySettings.RWR_WINDOW_SCALE_MAX + ? BDArmorySettings.RWR_WINDOW_SCALE_MAX + : BDArmorySettings.RWR_WINDOW_SCALE; + BDArmorySettings.RWR_WINDOW_SCALE = + BDArmorySettings.RWR_WINDOW_SCALE_MIN > BDArmorySettings.RWR_WINDOW_SCALE + ? BDArmorySettings.RWR_WINDOW_SCALE_MIN + : BDArmorySettings.RWR_WINDOW_SCALE; + } + + public static void PingRWR(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime) + { + if (OnRadarPing != null) + { + OnRadarPing(v, source, type, persistTime); + } + } + + public static void PingRWR(Ray ray, float fov, RWRThreatTypes type, float persistTime) + { + List.Enumerator vessel = FlightGlobals.Vessels.GetEnumerator(); + while (vessel.MoveNext()) + { + if (vessel.Current == null || !vessel.Current.loaded) continue; + Vector3 dirToVessel = vessel.Current.transform.position - ray.origin; + if (Vector3.Angle(ray.direction, dirToVessel) < fov / 2) + { + PingRWR(vessel.Current, ray.origin, type, persistTime); + } + } + vessel.Dispose(); + } + + public static void WarnMissileLaunch(Vector3 source, Vector3 direction) + { + OnMissileLaunch?.Invoke(source, direction); + } + } +} diff --git a/BDArmory/Modules/RocketLauncher.cs b/BDArmory/Modules/RocketLauncher.cs new file mode 100644 index 000000000..2d580b69e --- /dev/null +++ b/BDArmory/Modules/RocketLauncher.cs @@ -0,0 +1,1080 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.Core.Utils; +using BDArmory.FX; +using BDArmory.Misc; +using BDArmory.UI; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Modules +{ + public class RocketLauncher : EngageableWeapon, IBDWeapon + { + public bool hasRocket = true; + + [KSPField(isPersistant = false)] public string rocketType; + + [KSPField(isPersistant = false)] public string rocketModelPath; + + [KSPField(isPersistant = false)] public float rocketMass; + + [KSPField(isPersistant = false)] public float thrust; + + [KSPField(isPersistant = false)] public float thrustTime; + + [KSPField(isPersistant = false)] public float blastRadius; + + [KSPField(isPersistant = false)] public float blastForce; + + [KSPField] public float blastHeat = -1; + + [KSPField(isPersistant = false)] public bool descendingOrder = true; + + [KSPField(isPersistant = false)] public string explModelPath = "BDArmory/Models/explosion/explosion"; + + [KSPField(isPersistant = false)] public string explSoundPath = "BDArmory/Sounds/explode1"; + + [KSPField] public float thrustDeviation = 0.10f; + + [KSPField] public float maxTargetingRange = 8000; + float currentTgtRange = 8000; + float predictedFlightTime = 1; + + public bool drawAimer; + + Vector3 rocketPrediction = Vector3.zero; + Texture2D aimerTexture; + + Transform[] rockets; + + public AudioSource sfAudioSource; + private BDStagingAreaGauge gauge; + + //animation + [KSPField] public string deployAnimationName; + [KSPField] public float deployAnimationSpeed = 1; + AnimationState deployAnimState; + bool hasDeployAnimation; + public bool deployed; + Coroutine deployAnimRoutine; + + public bool readyToFire = true; + + public Vessel legacyGuardTarget = null; + public float lastAutoFiredTime; + public float autoRippleRate = 0; + public float autoFireStartTime = 0; + public float autoFireDuration = 0; + + //turret + [KSPField] public int turretID = 0; + public ModuleTurret turret; + Vector3 trajectoryOffset = Vector3.zero; + public MissileFire weaponManager; + bool targetInTurretView = true; + + public float yawRange + { + get { return turret ? turret.yawRange : 0; } + } + + public float maxPitch + { + get { return turret ? turret.maxPitch : 0; } + } + + public float minPitch + { + get { return turret ? turret.minPitch : 0; } + } + + Vector3 targetPosition; + public Vector3? FiringSolutionVector => targetPosition.IsZero() ? (Vector3?)null : (targetPosition - rockets[0].parent.transform.position).normalized; + + double lastRocketsLeft; + double rocketsMax; + + //weapon interface + public Part GetPart() + { + return part; + } + + public WeaponClasses GetWeaponClass() + { + return WeaponClasses.Rocket; + } + + public string GetSubLabel() + { + return string.Empty; + } + + public string GetMissileType() + { + return string.Empty; + } + + [KSPAction("Fire")] + public void AGFire(KSPActionParam param) + { + FireRocket(); + } + + [KSPEvent(guiActive = true, guiName = "#LOC_BDArmory_Fire", active = true)]//Fire + public void GuiFire() + { + FireRocket(); + } + + [KSPEvent(guiActive = true, guiName = "#LOC_BDArmory_Jettison", active = true, guiActiveEditor = false)]//Jettison + public void Jettison() + { + if (turret) + { + return; + } + + part.decouple(0); + if (BDArmorySetup.Instance.ActiveWeaponManager != null) + BDArmorySetup.Instance.ActiveWeaponManager.UpdateList(); + } + + [KSPEvent(guiActive = false, guiName = "#LOC_BDArmory_ToggleTurret", guiActiveEditor = false)]//Toggle Turret + public void ToggleTurret() + { + if (deployed) + { + DisableTurret(); + } + else + { + EnableTurret(); + } + } + + public void EnableTurret() + { + deployed = true; + drawAimer = true; + hasReturned = false; + + if (returnRoutine != null) + { + StopCoroutine(returnRoutine); + returnRoutine = null; + } + + if (hasDeployAnimation) + { + if (deployAnimRoutine != null) + { + StopCoroutine(deployAnimRoutine); + } + deployAnimRoutine = StartCoroutine(DeployAnimRoutine(true)); + } + else + { + readyToFire = true; + } + } + + public void DisableTurret() + { + deployed = false; + readyToFire = false; + drawAimer = false; + hasReturned = false; + targetInTurretView = false; + + if (returnRoutine != null) + { + StopCoroutine(returnRoutine); + } + returnRoutine = StartCoroutine(ReturnRoutine()); + + if (hasDeployAnimation) + { + if (deployAnimRoutine != null) + { + StopCoroutine(deployAnimRoutine); + } + + deployAnimRoutine = StartCoroutine(DeployAnimRoutine(false)); + } + } + + bool hasReturned = true; + Coroutine returnRoutine; + + IEnumerator ReturnRoutine() + { + if (deployed) + { + hasReturned = false; + yield break; + } + + yield return new WaitForSeconds(0.25f); + + while (!turret.ReturnTurret()) + { + yield return new WaitForFixedUpdate(); + } + + hasReturned = true; + } + + void SetupAudio() + { + sfAudioSource = gameObject.AddComponent(); + sfAudioSource.minDistance = 1; + sfAudioSource.maxDistance = 2000; + sfAudioSource.dopplerLevel = 0; + sfAudioSource.priority = 230; + sfAudioSource.spatialBlend = 1; + + UpdateVolume(); + BDArmorySetup.OnVolumeChange += UpdateVolume; + } + + void UpdateVolume() + { + if (sfAudioSource) + { + sfAudioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + } + + public void Start() + { + // extension for feature_engagementenvelope + InitializeEngagementRange(0, maxTargetingRange); + + SetupAudio(); + + if (HighLogic.LoadedSceneIsFlight) + { + part.force_activate(); + + aimerTexture = BDArmorySetup.Instance.greenPointCircleTexture; + // GameDatabase.Instance.GetTexture("BDArmory/Textures/grayCircle", false); + + MakeRocketArray(); + UpdateRocketScales(); + + if (shortName == string.Empty) + { + shortName = part.partInfo.title; + } + + UpdateAudio(); + BDArmorySetup.OnVolumeChange += UpdateAudio; + + gauge = (BDStagingAreaGauge)part.AddModule("BDStagingAreaGauge"); + gauge.AmmoName = rocketType; + gauge.AudioSource = sfAudioSource; + } + + if (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor) + { + List.Enumerator turr = part.FindModulesImplementing().GetEnumerator(); + while (turr.MoveNext()) + { + if (turr.Current == null) continue; + if (turr.Current.turretID != turretID) continue; + turret = turr.Current; + targetInTurretView = false; + break; + } + turr.Dispose(); + + if (turret) + { + Events["GuiFire"].guiActive = false; + Events["Jettison"].guiActive = false; + Actions["AGFire"].active = false; + + if (HighLogic.LoadedSceneIsFlight) + { + Events["ToggleTurret"].guiActive = true; + } + } + + if (!string.IsNullOrEmpty(deployAnimationName)) + { + deployAnimState = Misc.Misc.SetUpSingleAnimation(deployAnimationName, part); + hasDeployAnimation = true; + + readyToFire = false; + } + } + + blastForce = BlastPhysicsUtils.CalculateExplosiveMass(blastRadius); + } + + IEnumerator DeployAnimRoutine(bool forward) + { + readyToFire = false; + BDArmorySetup.Instance.UpdateCursorState(); + + if (forward) + { + while (deployAnimState.normalizedTime < 1) + { + deployAnimState.speed = deployAnimationSpeed; + yield return null; + } + + deployAnimState.normalizedTime = 1; + } + else + { + while (!hasReturned) + { + deployAnimState.speed = 0; + yield return null; + } + + while (deployAnimState.normalizedTime > 0) + { + deployAnimState.speed = -deployAnimationSpeed; + yield return null; + } + + deployAnimState.normalizedTime = 0; + } + + deployAnimState.speed = 0; + + readyToFire = deployed; + BDArmorySetup.Instance.UpdateCursorState(); + } + + void UpdateAudio() + { + if (sfAudioSource) + { + sfAudioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + } + + void OnDestroy() + { + BDArmorySetup.OnVolumeChange -= UpdateAudio; + } + + public void FixedUpdate() + { + if (!HighLogic.LoadedSceneIsFlight || !vessel.IsControllable) + { + return; + } + + SimulateTrajectory(); + + currentTgtRange = maxTargetingRange; + + if (deployed && readyToFire && (turret || weaponManager?.AI?.pilotEnabled == true)) + { + Aim(); + } + else + { + targetPosition = Vector3.zero; + } + } + + public void Update() + { + if (HighLogic.LoadedSceneIsFlight && !vessel.packed) + { + if (readyToFire && deployed) + { + if (returnRoutine != null) + { + StopCoroutine(returnRoutine); + returnRoutine = null; + } + + if (weaponManager && weaponManager.guardMode && weaponManager.selectedWeaponString == GetShortName()) + { + if (Time.time - autoFireStartTime < autoFireDuration) + { + float fireInterval = 0.5f; + if (autoRippleRate > 0) fireInterval = 60f / autoRippleRate; + if (Time.time - lastAutoFiredTime > fireInterval) + { + FireRocket(); + lastAutoFiredTime = Time.time; + } + } + } + else if ((!weaponManager || + (weaponManager.selectedWeaponString == GetShortName() && !weaponManager.guardMode))) + { + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.WEAP_FIRE_KEY) && + (vessel.isActiveVessel || BDArmorySettings.REMOTE_SHOOTING)) + { + FireRocket(); + } + } + } + + if (GetRocketResource().amount != lastRocketsLeft) + { + UpdateRocketScales(); + lastRocketsLeft = GetRocketResource().amount; + } + + if (vessel.isActiveVessel) + { + gauge.UpdateAmmoMeter((float)(lastRocketsLeft / rocketsMax)); + } + } + } + + bool mouseAiming; + + void Aim() + { + mouseAiming = false; + if (weaponManager && (weaponManager.slavingTurrets || weaponManager.guardMode || weaponManager.AI?.pilotEnabled == true)) + { + SlavedAim(); + } + else + { + if (vessel.isActiveVessel || BDArmorySettings.REMOTE_SHOOTING) + { + MouseAim(); + } + } + } + + void SlavedAim() + { + Vector3 targetVel; + Vector3 targetAccel; + if (weaponManager.slavingTurrets) + { + targetPosition = weaponManager.slavedPosition; + targetVel = weaponManager.slavedVelocity; + targetAccel = weaponManager.slavedAcceleration; + + //targetPosition -= vessel.Velocity * predictedFlightTime; + } + else if (legacyGuardTarget) + { + targetPosition = legacyGuardTarget.CoM; + targetVel = legacyGuardTarget.Velocity(); + targetAccel = legacyGuardTarget.acceleration; + } + else + { + targetInTurretView = false; + return; + } + + currentTgtRange = Vector3.Distance(targetPosition, rockets[0].parent.transform.position); + + targetPosition += trajectoryOffset; + targetPosition += targetVel * predictedFlightTime; + targetPosition += 0.5f * targetAccel * predictedFlightTime * predictedFlightTime; + + turret.AimToTarget(targetPosition); + targetInTurretView = turret.TargetInRange(targetPosition, 2, maxTargetingRange); + } + + void MouseAim() + { + mouseAiming = true; + Vector3 targetPosition; + // float maxTargetingRange = 8000; + + float targetDistance; + + //MouseControl + Vector3 mouseAim = new Vector3(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, 0); + Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mouseAim); + RaycastHit hit; + if (Physics.Raycast(ray, out hit, maxTargetingRange, 557057)) + { + targetPosition = hit.point; + + //aim through self vessel if occluding mouseray + Part p = hit.collider.gameObject.GetComponentInParent(); + if (p && p.vessel && p.vessel == vessel) + { + targetPosition = ray.direction * maxTargetingRange + FlightCamera.fetch.mainCamera.transform.position; + } + + targetDistance = Vector3.Distance(hit.point, rockets[0].parent.position); + } + else + { + targetPosition = (ray.direction * (maxTargetingRange + (FlightCamera.fetch.Distance * 0.75f))) + + FlightCamera.fetch.mainCamera.transform.position; + targetDistance = maxTargetingRange; + } + + currentTgtRange = targetDistance; + + targetPosition += trajectoryOffset; + + turret.AimToTarget(targetPosition); + targetInTurretView = turret.TargetInRange(targetPosition, 2, maxTargetingRange); + } + + public void FireRocket() + { + if (!readyToFire) return; + if (!targetInTurretView) return; + + PartResource rocketResource = GetRocketResource(); + + if (rocketResource == null) + { + Debug.Log(part.name + " doesn't carry the rocket resource it was meant to"); + return; + } + + int rocketsLeft = (int)Math.Floor(rocketResource.amount); + + if (BDArmorySettings.INFINITE_AMMO && rocketsLeft < 1) + rocketsLeft = 1; + + if (rocketsLeft >= 1) + { + Transform currentRocketTfm = rockets[rocketsLeft - 1]; + + GameObject rocketObj = GameDatabase.Instance.GetModel(rocketModelPath); + rocketObj = + (GameObject)Instantiate(rocketObj, currentRocketTfm.position, currentRocketTfm.parent.rotation); + rocketObj.transform.rotation = currentRocketTfm.parent.rotation; + rocketObj.transform.localScale = part.rescaleFactor * Vector3.one; + currentRocketTfm.localScale = Vector3.zero; + Rocket rocket = rocketObj.AddComponent(); + rocket.explModelPath = explModelPath; + rocket.explSoundPath = explSoundPath; + rocket.spawnTransform = currentRocketTfm; + rocket.mass = rocketMass; + rocket.blastForce = blastForce; + rocket.blastHeat = blastHeat; + rocket.blastRadius = blastRadius; + rocket.thrust = thrust; + rocket.thrustTime = thrustTime; + rocket.randomThrustDeviation = thrustDeviation; + + rocket.sourceVessel = vessel; + rocketObj.SetActive(true); + rocketObj.transform.SetParent(currentRocketTfm.parent); + rocket.parentRB = part.rb; + + sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/launch")); + if (!BDArmorySettings.INFINITE_AMMO) + rocketResource.amount--; + + lastRocketsLeft = rocketResource.amount; + } + } + + void SimulateTrajectory() + { + if ((BDArmorySettings.AIM_ASSIST && BDArmorySettings.DRAW_AIMERS && drawAimer && vessel.isActiveVessel) || + (weaponManager && weaponManager.guardMode && weaponManager.selectedWeaponString == GetShortName())) + { + float simTime = 0; + Transform fireTransform = rockets[0].parent; + Vector3 pointingDirection = fireTransform.forward; + Vector3 simVelocity = part.rb.velocity; + Vector3 simCurrPos = fireTransform.position + (part.rb.velocity * Time.fixedDeltaTime); + Vector3 simPrevPos = fireTransform.position + (part.rb.velocity * Time.fixedDeltaTime); + Vector3 simStartPos = fireTransform.position + (part.rb.velocity * Time.fixedDeltaTime); + bool simulating = true; + float simDeltaTime = 0.02f; + List pointPositions = new List(); + pointPositions.Add(simCurrPos); + + bool slaved = turret && weaponManager && (weaponManager.slavingTurrets || weaponManager.guardMode); + float atmosMultiplier = + Mathf.Clamp01(2.5f * + (float) + FlightGlobals.getAtmDensity(vessel.staticPressurekPa, vessel.externalTemperature, + vessel.mainBody)); + while (simulating) + { + RaycastHit hit; + + if (simTime > thrustTime) + { + simDeltaTime = 0.1f; + } + + if (simTime > 0.04f) + { + simDeltaTime = 0.02f; + if (simTime < thrustTime) + { + simVelocity += thrust / rocketMass * simDeltaTime * pointingDirection; + } + + //rotation (aero stabilize) + pointingDirection = Vector3.RotateTowards(pointingDirection, + simVelocity + Krakensbane.GetFrameVelocity(), + atmosMultiplier * (0.5f * (simTime)) * 50 * simDeltaTime * Mathf.Deg2Rad, 0); + } + + //gravity + simVelocity += FlightGlobals.getGeeForceAtPosition(simCurrPos) * simDeltaTime; + + simCurrPos += simVelocity * simDeltaTime; + pointPositions.Add(simCurrPos); + if (!mouseAiming && !slaved) + { + if (simTime > 0.1f && Physics.Raycast(simPrevPos, simCurrPos - simPrevPos, out hit, + Vector3.Distance(simPrevPos, simCurrPos), 9076737)) + { + rocketPrediction = hit.point; + simulating = false; + break; + } + else if (FlightGlobals.getAltitudeAtPos(simCurrPos) < 0) + { + rocketPrediction = simCurrPos; + simulating = false; + break; + } + } + + simPrevPos = simCurrPos; + + if ((simStartPos - simCurrPos).sqrMagnitude > currentTgtRange * currentTgtRange) + { + rocketPrediction = simStartPos + (simCurrPos - simStartPos).normalized * currentTgtRange; + //rocketPrediction = simCurrPos; + simulating = false; + } + simTime += simDeltaTime; + } + + Vector3 pointingPos = fireTransform.position + (fireTransform.forward * currentTgtRange); + trajectoryOffset = pointingPos - rocketPrediction; + predictedFlightTime = simTime; + + if (BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) + { + Vector3[] pointsArray = pointPositions.ToArray(); + if (gameObject.GetComponent() == null) + { + LineRenderer lr = gameObject.AddComponent(); + lr.startWidth = .1f; + lr.endWidth = .1f; + lr.positionCount = pointsArray.Length; + for (int i = 0; i < pointsArray.Length; i++) + { + lr.SetPosition(i, pointsArray[i]); + } + } + else + { + LineRenderer lr = gameObject.GetComponent(); + lr.enabled = true; + lr.positionCount = pointsArray.Length; + for (int i = 0; i < pointsArray.Length; i++) + { + lr.SetPosition(i, pointsArray[i]); + } + } + } + else + { + if (gameObject.GetComponent() != null) + { + gameObject.GetComponent().enabled = false; + } + } + } + + //for straight aimer + else if (BDArmorySettings.DRAW_AIMERS && drawAimer && vessel.isActiveVessel) + { + RaycastHit hit; + float distance = 2500; + if (Physics.Raycast(transform.position, transform.forward, out hit, distance, 9076737)) + { + rocketPrediction = hit.point; + } + else + { + rocketPrediction = transform.position + (transform.forward * distance); + } + } + } + + void OnGUI() + { + if (drawAimer && vessel.isActiveVessel && BDArmorySettings.DRAW_AIMERS && !MapView.MapIsEnabled) + { + float size = 30; + + Vector3 aimPosition = FlightCamera.fetch.mainCamera.WorldToViewportPoint(rocketPrediction); + + Rect drawRect = new Rect(aimPosition.x * Screen.width - (0.5f * size), + (1 - aimPosition.y) * Screen.height - (0.5f * size), size, size); + float cameraAngle = Vector3.Angle(FlightCamera.fetch.GetCameraTransform().forward, + rocketPrediction - FlightCamera.fetch.mainCamera.transform.position); + if (cameraAngle < 90) GUI.DrawTexture(drawRect, aimerTexture); + } + } + + void MakeRocketArray() + { + Transform rocketsTransform = part.FindModelTransform("rockets"); + int numOfRockets = rocketsTransform.childCount; + rockets = new Transform[numOfRockets]; + + for (int i = 0; i < numOfRockets; i++) + { + string rocketName = rocketsTransform.GetChild(i).name; + int rocketIndex = int.Parse(rocketName.Substring(7)) - 1; + rockets[rocketIndex] = rocketsTransform.GetChild(i); + } + + if (!descendingOrder) Array.Reverse(rockets); + } + + public PartResource GetRocketResource() + { + using (var res = part.Resources.GetEnumerator()) + while (res.MoveNext()) + { + if (res.Current == null) continue; + if (res.Current.resourceName == rocketType) return res.Current; + } + return null; + } + + void UpdateRocketScales() + { + // This is a backup method only, rockets will be rescaled to zero on firing, + // so this will be called only on start and if something weird happens. + PartResource rocketResource = GetRocketResource(); + var rocketsLeft = Math.Floor(rocketResource.amount); + rocketsMax = rocketResource.maxAmount; + for (int i = 0; i < rocketsMax; i++) + { + if (i < rocketsLeft) rockets[i].localScale = Vector3.one; + else rockets[i].localScale = Vector3.zero; + } + } + + // RMB info in editor + public override string GetInfo() + { + StringBuilder output = new StringBuilder(); + output.Append(Environment.NewLine); + output.AppendLine("Weapon Type: Rocket Launcher"); + output.AppendLine($"Rocket Type: {rocketType}"); + output.AppendLine($"Max Range: {maxTargetingRange} m"); + + output.AppendLine($"Blast:"); + output.AppendLine($"- radius: {blastRadius}"); + output.AppendLine($"- power: {blastForce}"); + output.AppendLine($"- heat: {blastHeat}"); + + return output.ToString(); + } + } + + public class Rocket : MonoBehaviour + { + public Transform spawnTransform; + public Vessel sourceVessel; + public float mass; + public float thrust; + public float thrustTime; + public float blastRadius; + public float blastForce; + public float blastHeat; + public string explModelPath; + public string explSoundPath; + + public float randomThrustDeviation = 0.05f; + + public Rigidbody parentRB; + + float startTime; + public AudioSource audioSource; + + Vector3 prevPosition; + Vector3 currPosition; + + float stayTime = 0.04f; + float lifeTime = 10; + + //bool isThrusting = true; + + Rigidbody rb; + + KSPParticleEmitter[] pEmitters; + + float randThrustSeed; + + void Start() + { + BDArmorySetup.numberOfParticleEmitters++; + + rb = gameObject.AddComponent(); + pEmitters = gameObject.GetComponentsInChildren(); + + IEnumerator pe = pEmitters.AsEnumerable().GetEnumerator(); + while (pe.MoveNext()) + { + if (pe.Current == null) continue; + if (FlightGlobals.getStaticPressure(transform.position) == 0 && pe.Current.useWorldSpace) + { + pe.Current.emit = false; + } + else if (pe.Current.useWorldSpace) + { + BDAGaplessParticleEmitter gpe = pe.Current.gameObject.AddComponent(); + gpe.rb = rb; + gpe.emit = true; + } + else + { + EffectBehaviour.AddParticleEmitter(pe.Current); + } + } + pe.Dispose(); + + prevPosition = transform.position; + currPosition = transform.position; + startTime = Time.time; + + rb.mass = mass; + rb.isKinematic = true; + //rigidbody.velocity = startVelocity; + if (!FlightGlobals.RefFrameIsRotating) rb.useGravity = false; + + rb.useGravity = false; + + randThrustSeed = UnityEngine.Random.Range(0f, 100f); + + SetupAudio(); + } + + void FixedUpdate() + { + //floating origin and velocity offloading corrections + if (!FloatingOrigin.Offset.IsZero() || !Krakensbane.GetFrameVelocity().IsZero()) + { + transform.position -= FloatingOrigin.OffsetNonKrakensbane; + prevPosition -= FloatingOrigin.OffsetNonKrakensbane; + } + + if (Time.time - startTime < stayTime && transform.parent != null) + { + transform.rotation = transform.parent.rotation; + transform.position = spawnTransform.position; + //+(transform.parent.rigidbody.velocity*Time.fixedDeltaTime); + } + else + { + if (transform.parent != null && parentRB) + { + transform.parent = null; + rb.isKinematic = false; + rb.velocity = parentRB.velocity + Krakensbane.GetFrameVelocityV3f(); + } + } + + if (rb && !rb.isKinematic) + { + //physics + if (FlightGlobals.RefFrameIsRotating) + { + rb.velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; + } + + //guidance and attitude stabilisation scales to atmospheric density. + float atmosMultiplier = + Mathf.Clamp01(2.5f * + (float) + FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), + FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody)); + + //model transform. always points prograde + transform.rotation = Quaternion.RotateTowards(transform.rotation, + Quaternion.LookRotation(rb.velocity + Krakensbane.GetFrameVelocity(), transform.up), + atmosMultiplier * (0.5f * (Time.time - startTime)) * 50 * Time.fixedDeltaTime); + + if (Time.time - startTime < thrustTime && Time.time - startTime > stayTime) + { + float random = randomThrustDeviation * (1 - (Mathf.PerlinNoise(4 * Time.time, randThrustSeed) * 2)); + float random2 = randomThrustDeviation * (1 - (Mathf.PerlinNoise(randThrustSeed, 4 * Time.time) * 2)); + rb.AddRelativeForce(new Vector3(random, random2, thrust)); + } + } + + if (Time.time - startTime > thrustTime) + { + //isThrusting = false; + IEnumerator pEmitter = pEmitters.AsEnumerable().GetEnumerator(); + while (pEmitter.MoveNext()) + { + if (pEmitter.Current == null) continue; + if (pEmitter.Current.useWorldSpace) + { + pEmitter.Current.minSize = Mathf.MoveTowards(pEmitter.Current.minSize, 0.1f, 0.05f); + pEmitter.Current.maxSize = Mathf.MoveTowards(pEmitter.Current.maxSize, 0.2f, 0.05f); + } + else + { + pEmitter.Current.minSize = Mathf.MoveTowards(pEmitter.Current.minSize, 0, 0.1f); + pEmitter.Current.maxSize = Mathf.MoveTowards(pEmitter.Current.maxSize, 0, 0.1f); + if (pEmitter.Current.maxSize == 0) + { + pEmitter.Current.emit = false; + } + } + } + pEmitter.Dispose(); + } + + if (Time.time - startTime > 0.1f + stayTime) + { + currPosition = transform.position; + float dist = (currPosition - prevPosition).magnitude; + Ray ray = new Ray(prevPosition, currPosition - prevPosition); + RaycastHit hit; + KerbalEVA hitEVA = null; + //if (Physics.Raycast(ray, out hit, dist, 2228224)) + //{ + // try + // { + // hitEVA = hit.collider.gameObject.GetComponentUpwards(); + // if (hitEVA != null) + // Debug.Log("[BDArmory]:Hit on kerbal confirmed!"); + // } + // catch (NullReferenceException) + // { + // Debug.Log("[BDArmory]:Whoops ran amok of the exception handler"); + // } + + // if (hitEVA && hitEVA.part.vessel != sourceVessel) + // { + // Detonate(hit.point); + // } + //} + + if (!hitEVA) + { + if (Physics.Raycast(ray, out hit, dist, 9076737)) + { + Part hitPart = null; + try + { + KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards(); + hitPart = eva ? eva.part : hit.collider.gameObject.GetComponentInParent(); + } + catch (NullReferenceException) + { + } + + if (hitPart == null || (hitPart != null && hitPart.vessel != sourceVessel)) + { + Detonate(hit.point); + } + } + else if (FlightGlobals.getAltitudeAtPos(transform.position) < 0) + { + Detonate(transform.position); + } + } + } + else if (FlightGlobals.getAltitudeAtPos(currPosition) <= 0) + { + Detonate(currPosition); + } + prevPosition = currPosition; + + if (Time.time - startTime > lifeTime) + { + Detonate(transform.position); + } + } + + void Update() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (BDArmorySetup.GameIsPaused) + { + if (audioSource.isPlaying) + { + audioSource.Stop(); + } + } + else + { + if (!audioSource.isPlaying) + { + audioSource.Play(); + } + } + } + } + + void Detonate(Vector3 pos) + { + BDArmorySetup.numberOfParticleEmitters--; + + ExplosionFx.CreateExplosion(pos, BlastPhysicsUtils.CalculateExplosiveMass(blastRadius), + explModelPath, explSoundPath, true); + + IEnumerator emitter = pEmitters.AsEnumerable().GetEnumerator(); + while (emitter.MoveNext()) + { + if (emitter.Current == null) continue; + if (!emitter.Current.useWorldSpace) continue; + emitter.Current.gameObject.AddComponent(); + emitter.Current.transform.parent = null; + } + emitter.Dispose(); + Destroy(gameObject); //destroy rocket on collision + } + + void SetupAudio() + { + audioSource = gameObject.AddComponent(); + audioSource.loop = true; + audioSource.minDistance = 1; + audioSource.maxDistance = 2000; + audioSource.dopplerLevel = 0.5f; + audioSource.volume = 0.9f * BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + audioSource.pitch = 1f; + audioSource.priority = 255; + audioSource.spatialBlend = 1; + + audioSource.clip = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rocketLoop"); + + UpdateVolume(); + BDArmorySetup.OnVolumeChange += UpdateVolume; + } + + void UpdateVolume() + { + if (audioSource) + { + audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + } + } + } +} diff --git a/BDArmory/Parts/GPSTargetInfo.cs b/BDArmory/Parts/GPSTargetInfo.cs new file mode 100644 index 000000000..dd87f65e7 --- /dev/null +++ b/BDArmory/Parts/GPSTargetInfo.cs @@ -0,0 +1,39 @@ +using System; +using BDArmory.Misc; + +namespace BDArmory.Parts +{ + [Serializable] + public struct GPSTargetInfo + { + public Vector3d gpsCoordinates; + + public string name; + + [NonSerialized] + public Vessel gpsVessel; + + public Vector3d worldPos + { + get + { + if (!FlightGlobals.currentMainBody) + return Vector3d.zero; + + return VectorUtils.GetWorldSurfacePostion(gpsCoordinates, FlightGlobals.currentMainBody); + } + } + + public GPSTargetInfo(Vector3d coords, string name, Vessel vessel = null) + { + gpsVessel = vessel; + gpsCoordinates = coords; + this.name = name; + } + + public bool EqualsTarget(GPSTargetInfo other) + { + return name == other.name && gpsCoordinates == other.gpsCoordinates && gpsVessel == other.gpsVessel; + } + } +} diff --git a/BDArmory/Parts/SeismicChargeFX.cs b/BDArmory/Parts/SeismicChargeFX.cs new file mode 100644 index 000000000..22b93850a --- /dev/null +++ b/BDArmory/Parts/SeismicChargeFX.cs @@ -0,0 +1,114 @@ +using System; +using BDArmory.Core.Extension; +using UnityEngine; + +namespace BDArmory.Parts +{ + public class SeismicChargeFX : MonoBehaviour + { + AudioSource audioSource; + + public static float originalShipVolume; + public static float originalMusicVolume; + public static float originalAmbienceVolume; + + float startTime; + + Transform lightFlare; + + Rigidbody rb; + + void Start() + { + transform.localScale = 2 * Vector3.one; + lightFlare = gameObject.transform.Find("lightFlare"); + + startTime = Time.time; + + audioSource = gameObject.AddComponent(); + audioSource.minDistance = 5000; + audioSource.maxDistance = 5000; + audioSource.dopplerLevel = 0f; + audioSource.pitch = UnityEngine.Random.Range(0.93f, 1f); + audioSource.volume = Mathf.Sqrt(originalShipVolume); + + audioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/seismicCharge")); + + rb = gameObject.AddComponent(); + rb.useGravity = false; + rb.velocity = Vector3.zero; + } + + void FixedUpdate() + { + lightFlare.LookAt(FlightCamera.fetch.mainCamera.transform.position, + FlightCamera.fetch.mainCamera.transform.up); + + if (Time.time - startTime < 1.25f) + { + // + GameSettings.SHIP_VOLUME = Mathf.MoveTowards(GameSettings.SHIP_VOLUME, 0, originalShipVolume / 0.7f); + GameSettings.MUSIC_VOLUME = Mathf.MoveTowards(GameSettings.MUSIC_VOLUME, 0, originalShipVolume / 0.7f); + GameSettings.AMBIENCE_VOLUME = Mathf.MoveTowards(GameSettings.AMBIENCE_VOLUME, 0, + originalShipVolume / 0.7f); + } + else if (Time.time - startTime < 7.35f / audioSource.pitch) + { + //make it fade in more slowly + GameSettings.SHIP_VOLUME = Mathf.MoveTowards(GameSettings.SHIP_VOLUME, originalShipVolume, + originalShipVolume / 3f * Time.fixedDeltaTime); + GameSettings.MUSIC_VOLUME = Mathf.MoveTowards(GameSettings.MUSIC_VOLUME, originalMusicVolume, + originalMusicVolume / 3f * Time.fixedDeltaTime); + GameSettings.AMBIENCE_VOLUME = Mathf.MoveTowards(GameSettings.AMBIENCE_VOLUME, originalAmbienceVolume, + originalAmbienceVolume / 3f * Time.fixedDeltaTime); + } + else + { + Destroy(gameObject); + } + } + + void OnTriggerEnter(Collider other) + { + //hitting parts + Part explodePart = null; + try + { + explodePart = other.gameObject.GetComponentUpwards(); + explodePart.Unpack(); + } + catch (NullReferenceException) + { + } + + if (explodePart != null) + { + explodePart.Destroy(); + } + else + { + //hitting buildings + DestructibleBuilding hitBuilding = null; + try + { + hitBuilding = other.gameObject.GetComponentUpwards(); + } + catch (NullReferenceException) + { + } + if (hitBuilding != null && hitBuilding.IsIntact) + { + hitBuilding.Demolish(); + } + } + } + + public static void CreateSeismicExplosion(Vector3 pos, Quaternion rot) + { + GameObject explosionModel = GameDatabase.Instance.GetModel("BDArmory/Models/seismicCharge/seismicExplosion"); + GameObject explosionObject = (GameObject)Instantiate(explosionModel, pos, rot); + explosionObject.SetActive(true); + explosionObject.AddComponent(); + } + } +} diff --git a/BDArmory/Parts/TGPCamRotator.cs b/BDArmory/Parts/TGPCamRotator.cs new file mode 100644 index 000000000..b11e8fa14 --- /dev/null +++ b/BDArmory/Parts/TGPCamRotator.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace BDArmory.Parts +{ + public class TGPCamRotator : MonoBehaviour + { + void OnPreRender() + { + if (TargetingCamera.Instance) + { + TargetingCamera.Instance.UpdateCamRotation(transform); + } + } + } +} diff --git a/BDArmory/Parts/TGPCameraEffects.cs b/BDArmory/Parts/TGPCameraEffects.cs new file mode 100644 index 000000000..8c1ce05ee --- /dev/null +++ b/BDArmory/Parts/TGPCameraEffects.cs @@ -0,0 +1,33 @@ +using BDArmory.Core; +using BDArmory.Shaders; +using UnityEngine; + +namespace BDArmory.Parts +{ + public class TGPCameraEffects : MonoBehaviour + { + public static Material grayscaleMaterial; + + public Texture textureRamp; + public float rampOffset; + + void Awake() + { + if (!grayscaleMaterial) + { + grayscaleMaterial = new Material(BDAShaderLoader.GrayscaleEffectShader); + grayscaleMaterial.SetTexture("_RampTex", textureRamp); + grayscaleMaterial.SetFloat("_RedPower", rampOffset); + grayscaleMaterial.SetFloat("_RedDelta", rampOffset); + } + } + + void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (BDArmorySettings.BW_TARGET_CAM || TargetingCamera.Instance.nvMode) + { + Graphics.Blit(source, destination, grayscaleMaterial); //apply grayscale + } + } + } +} diff --git a/BDArmory/Parts/TargetingCamera.cs b/BDArmory/Parts/TargetingCamera.cs new file mode 100644 index 000000000..550e9bb39 --- /dev/null +++ b/BDArmory/Parts/TargetingCamera.cs @@ -0,0 +1,322 @@ +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Modules; +using UnityEngine; + +namespace BDArmory.Parts +{ + public class TargetingCamera : MonoBehaviour + { + public static TargetingCamera Instance; + public static bool ReadyForUse; + public RenderTexture targetCamRenderTexture; + TGPCameraEffects camEffects; + Light nvLight; + public bool nvMode = false; + + private Texture2D reticleTex; + + public Texture2D ReticleTexture + { + get + { + if (reticleTex != null) + { + return reticleTex; + } + else + { + reticleTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/camReticle", false); + return reticleTex; + } + } + } + + Camera[] cameras; + public static Transform cameraTransform; + + bool cameraEnabled; + + float currentFOV = 60; + + void Awake() + { + if (Instance) + { + Destroy(gameObject); + return; + } + else + { + Instance = this; + } + } + + void Start() + { + GameEvents.onVesselChange.Add(VesselChange); + } + + public void UpdateCamRotation(Transform tf) + { + if (cameras != null && cameras[0] != null) + { + tf.rotation = cameras[0].transform.rotation; + } + } + + public void SetFOV(float fov) + { + if (fov == currentFOV) + { + return; + } + + if (cameras == null || cameras[0] == null) + { + if (cameraEnabled) + { + DisableCamera(); + } + return; + } + + for (int i = 0; i < cameras.Length; i++) + { + cameras[i].fieldOfView = fov; + } + currentFOV = fov; + } + + void VesselChange(Vessel v) + { + if (!v.isActiveVessel) + { + return; + } + + bool moduleFound = false; + List.Enumerator mtc = v.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + Debug.Log("[BDArmory] : Vessel switched to vessel with targeting camera. Refreshing camera state."); + + if (mtc.Current.cameraEnabled) + { + mtc.Current.DelayedEnable(); + } + else + { + mtc.Current.DisableCamera(); + } + moduleFound = true; + } + mtc.Dispose(); + + if (!moduleFound) + { + DisableCamera(); + ModuleTargetingCamera.windowIsOpen = false; + } + } + + public void EnableCamera(Transform parentTransform) + { + if (cameraTransform) + { + cameraTransform.gameObject.SetActive(true); + } + + SetupCamera(parentTransform); + + for (int i = 0; i < cameras.Length; i++) + { + cameras[i].enabled = false; + } + + cameraEnabled = true; + + ReadyForUse = true; + } + + void RenderCameras() + { + cameras[3].Render(); + cameras[2].Render(); + + Color origAmbientColor = RenderSettings.ambientLight; + if (nvMode) + { + RenderSettings.ambientLight = new Color(0.5f, 0.5f, 0.5f, 1); + nvLight.enabled = true; + } + cameras[1].Render(); + cameras[0].Render(); + + nvLight.enabled = false; + if (nvMode) + { + RenderSettings.ambientLight = origAmbientColor; + } + } + + void LateUpdate() + { + if (cameraEnabled) + { + if (cameras == null || cameras[0] == null) + { + DisableCamera(); + return; + } + RenderCameras(); + } + } + + public void DisableCamera() + { + if (cameraTransform) + { + cameraTransform.parent = null; + cameraTransform.gameObject.SetActive(false); + } + + if (cameras != null && cameras[0] != null) + { + for (int i = 0; i < cameras.Length; i++) + { + cameras[i].enabled = false; + } + } + + cameraEnabled = false; + } + + void SetupCamera(Transform parentTransform) + { + if (!parentTransform) + { + Debug.Log("Targeting camera tried setup but parent transform is null"); + return; + } + + if (cameraTransform == null) + { + cameraTransform = (new GameObject("targetCamObject")).transform; + } + + Debug.Log("Setting target camera parent"); + cameraTransform.parent = parentTransform; + cameraTransform.localPosition = Vector3.zero; + cameraTransform.localRotation = Quaternion.identity; + + if (targetCamRenderTexture == null) + { + int res = Mathf.RoundToInt(BDArmorySettings.TARGET_CAM_RESOLUTION); + targetCamRenderTexture = new RenderTexture(res, res, 24); + targetCamRenderTexture.antiAliasing = 1; + targetCamRenderTexture.Create(); + } + + if (cameras != null && cameras[0] != null) + { + return; + } + + //cam setup + cameras = new Camera[4]; + + Camera fCamNear = FlightCamera.fetch.cameras[0]; + Camera fCamFar = FlightCamera.fetch.cameras[1]; + + //flight cameras + //nearCam + GameObject cam1Obj = new GameObject(); + Camera nearCam = cam1Obj.AddComponent(); + nearCam.CopyFrom(fCamNear); + nearCam.transform.parent = cameraTransform; + nearCam.transform.localRotation = Quaternion.identity; + nearCam.transform.localPosition = Vector3.zero; + nearCam.transform.localScale = Vector3.one; + nearCam.targetTexture = targetCamRenderTexture; + cameras[0] = nearCam; + + TGPCameraEffects ge1 = cam1Obj.AddComponent(); + ge1.textureRamp = GameDatabase.Instance.GetTexture("BDArmory/Textures/grayscaleRamp", false); + ge1.rampOffset = 0; + camEffects = ge1; + + //farCam + GameObject cam2Obj = new GameObject(); + Camera farCam = cam2Obj.AddComponent(); + farCam.CopyFrom(fCamFar); + farCam.transform.parent = cameraTransform; + farCam.transform.localRotation = Quaternion.identity; + farCam.transform.localPosition = Vector3.zero; + farCam.transform.localScale = Vector3.one; + farCam.targetTexture = targetCamRenderTexture; + cameras[1] = farCam; + + //skybox camera + GameObject skyCamObj = new GameObject(); + Camera skyCam = skyCamObj.AddComponent(); + Camera mainSkyCam = FindCamera("Camera ScaledSpace"); + skyCam.CopyFrom(mainSkyCam); + skyCam.transform.parent = mainSkyCam.transform; + skyCam.transform.localRotation = Quaternion.identity; + skyCam.transform.localPosition = Vector3.zero; + skyCam.transform.localScale = Vector3.one; + skyCam.targetTexture = targetCamRenderTexture; + cameras[cameras.Length - 2] = skyCam; + skyCamObj.AddComponent(); + + //galaxy camera + GameObject galaxyCamObj = new GameObject(); + Camera galaxyCam = galaxyCamObj.AddComponent(); + Camera mainGalaxyCam = FindCamera("GalaxyCamera"); + galaxyCam.CopyFrom(mainGalaxyCam); + galaxyCam.transform.parent = mainGalaxyCam.transform; + galaxyCam.transform.position = Vector3.zero; + galaxyCam.transform.localRotation = Quaternion.identity; + galaxyCam.transform.localScale = Vector3.one; + galaxyCam.targetTexture = targetCamRenderTexture; + cameras[cameras.Length - 1] = galaxyCam; + galaxyCamObj.AddComponent(); + + nvLight = new GameObject().AddComponent(); + nvLight.transform.parent = cameraTransform; + nvLight.transform.localPosition = Vector3.zero; + nvLight.transform.localRotation = Quaternion.identity; + nvLight.type = LightType.Directional; + nvLight.intensity = 2; + nvLight.shadows = LightShadows.None; + + nvLight.cullingMask = 1 << 0; + nvLight.enabled = false; + } + + private Camera FindCamera(string cameraName) + { + foreach (Camera cam in Camera.allCameras) + { + if (cam.name == cameraName) + { + return cam; + } + } + Debug.Log("Couldn't find " + cameraName); + return null; + } + + void OnDestroy() + { + ReadyForUse = false; + GameEvents.onVesselChange.Remove(VesselChange); + } + + public static bool IsTGPCamera(Camera c) + { + return c.transform == cameraTransform; + } + } +} diff --git a/BahaTurret/Properties/AssemblyInfo.cs b/BDArmory/Properties/AssemblyInfo.cs similarity index 74% rename from BahaTurret/Properties/AssemblyInfo.cs rename to BDArmory/Properties/AssemblyInfo.cs index 881f6888b..da1506030 100644 --- a/BahaTurret/Properties/AssemblyInfo.cs +++ b/BDArmory/Properties/AssemblyInfo.cs @@ -1,25 +1,24 @@ using System.Reflection; -using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. -[assembly: AssemblyTitle("BahaTurret")] +[assembly: AssemblyTitle("BDArmory")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("Paolo Encarnacion")] +[assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] - - // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion("1.0")] +[assembly: AssemblyVersion("1.3.5.0")] +[assembly: AssemblyFileVersion("1.3.5.0")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. @@ -28,5 +27,6 @@ //[assembly: AssemblyKeyFile("")] //ksp assembly -[assembly: KSPAssembly("BahaTurret", 1, 0)] +[assembly: KSPAssembly("BDArmory", 1, 0)] +[assembly: Guid("70e0663f-1b79-45e9-9a3f-0e2281d0640f")] diff --git a/BDArmory/Radar/RadarDisplayData.cs b/BDArmory/Radar/RadarDisplayData.cs new file mode 100644 index 000000000..9202ab943 --- /dev/null +++ b/BDArmory/Radar/RadarDisplayData.cs @@ -0,0 +1,16 @@ +using BDArmory.Modules; +using BDArmory.Targeting; +using UnityEngine; + +namespace BDArmory.Radar +{ + public struct RadarDisplayData + { + public Vessel vessel; + public Vector2 pingPosition; + public bool locked; + public ModuleRadar detectedByRadar; + public TargetSignatureData targetData; + public float signalPersistTime; + } +} diff --git a/BDArmory/Radar/RadarUtils.cs b/BDArmory/Radar/RadarUtils.cs new file mode 100644 index 000000000..3273b48f6 --- /dev/null +++ b/BDArmory/Radar/RadarUtils.cs @@ -0,0 +1,979 @@ +using System.Collections.Generic; +using BDArmory.Control; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.CounterMeasure; +using BDArmory.Misc; +using BDArmory.Modules; +using BDArmory.Shaders; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Radar +{ + public static class RadarUtils + { + private static bool rcsSetupCompleted = false; + private static int radarResolution = 128; + + private static RenderTexture rcsRenderingFrontal; + private static RenderTexture rcsRenderingLateral; + private static RenderTexture rcsRenderingVentral; + private static Camera radarCam; + + private static Texture2D drawTextureFrontal; + public static Texture2D GetTextureFrontal { get { return drawTextureFrontal; } } + private static Texture2D drawTextureLateral; + public static Texture2D GetTextureLateral { get { return drawTextureLateral; } } + private static Texture2D drawTextureVentral; + public static Texture2D GetTextureVentral { get { return drawTextureVentral; } } + + // additional anti-exploit 45 offset renderings + private static Texture2D drawTextureFrontal45; + public static Texture2D GetTextureFrontal45 { get { return drawTextureFrontal45; } } + private static Texture2D drawTextureLateral45; + public static Texture2D GetTextureLateral45 { get { return drawTextureLateral45; } } + private static Texture2D drawTextureVentral45; + public static Texture2D GetTextureVentral45 { get { return drawTextureVentral45; } } + + internal static float rcsFrontal; // internal so that editor analysis window has access to the details + internal static float rcsLateral; // dito + internal static float rcsVentral; // dito + internal static float rcsFrontal45; // dito + internal static float rcsLateral45; // dito + internal static float rcsVentral45; // dito + internal static float rcsTotal; // dito + + internal const float RCS_NORMALIZATION_FACTOR = 16.0f; //IMPORTANT FOR RCS CALCULATION! DO NOT CHANGE! (1x1 structural panel frontally facing should yield 1 m^2 of rcs!) + internal const float RCS_MISSILES = 999f; //default rcs value for missiles if not configured in the part config + internal const float RWR_PING_RANGE_FACTOR = 2.0f; + internal const float RADAR_IGNORE_DISTANCE_SQR = 100f; + internal const float ACTIVE_MISSILE_PING_PERISTS_TIME = 0.2f; + internal const float MISSILE_DEFAULT_LOCKABLE_RCS = 5f; + + /// + /// Get a vessel radar siganture, including all modifiers (ECM, stealth, ...) + /// + public static TargetInfo GetVesselRadarSignature(Vessel v) + { + //1. baseSig = GetVesselRadarCrossSection + TargetInfo ti = GetVesselRadarCrossSection(v); + + //2. modifiedSig = GetVesselModifiedSignature(baseSig) //ECM-jammers with rcs reduction effect; other rcs reductions (stealth) + float modifiedSig = GetVesselModifiedSignature(v, ti); + + return ti; + } + + /// + /// Internal method: get a vessel base radar signature + /// + private static TargetInfo GetVesselRadarCrossSection(Vessel v) + { + //read vesseltargetinfo, or render against radar cameras + TargetInfo ti = v.gameObject.GetComponent(); + + if (ti == null) + { + // add targetinfo to vessel + ti = v.gameObject.AddComponent(); + } + + if (ti.isMissile) + { + // missile handling: get signature from missile config, unless it is radaractive, then use old legacy special handling. + // LEGACY special handling missile: should always be detected, hence signature is set to maximum + MissileBase missile = ti.MissileBaseModule; + if (missile != null) + { + if (missile.ActiveRadar) + ti.radarBaseSignature = RCS_MISSILES; + else + ti.radarBaseSignature = missile.missileRadarCrossSection; + + ti.radarBaseSignatureNeedsUpdate = false; + } + } + + if (ti.radarBaseSignature == -1 || ti.radarBaseSignatureNeedsUpdate) + { + // is it just some debris? then dont bother doing a real rcs rendering and just fake it with the parts mass + if (v.vesselType == VesselType.Debris && !v.IsControllable) + { + ti.radarBaseSignature = v.GetTotalMass(); + } + else + { + // perform radar rendering to obtain base cross section + ti.radarBaseSignature = RenderVesselRadarSnapshot(v, v.transform); + } + + ti.radarBaseSignatureNeedsUpdate = false; + ti.alreadyScheduledRCSUpdate = false; + } + + return ti; + } + + /// + /// Internal method: get a vessels siganture modifiers (ecm, stealth, ...) + /// + private static float GetVesselModifiedSignature(Vessel v, TargetInfo ti) + { + ti.radarModifiedSignature = ti.radarBaseSignature; + ti.radarLockbreakFactor = 1; + + // + // read vessel ecminfo for active jammers and calculate effects: + VesselECMJInfo vesseljammer = v.gameObject.GetComponent(); + if (vesseljammer) + { + //1) read vessel ecminfo for jammers with RCS reduction effect and multiply factor + ti.radarModifiedSignature *= vesseljammer.rcsReductionFactor; + + //2) increase in detectability relative to jammerstrength and vessel rcs signature: + // rcs_factor = jammerStrength / modifiedSig / 100 + 1.0f + ti.radarModifiedSignature *= (((vesseljammer.jammerStrength / ti.radarModifiedSignature) / 100) + 1.0f); + + //3) garbling due to overly strong jamming signals relative to jammer's strength in relation to vessel rcs signature: + // jammingDistance = (jammerstrength / baseSig / 100 + 1.0) x js + ti.radarJammingDistance = ((vesseljammer.jammerStrength / ti.radarBaseSignature / 100) + 1.0f) * vesseljammer.jammerStrength; + + //4) lockbreaking strength relative to jammer's lockbreak strength in relation to vessel rcs signature: + // lockbreak_factor = baseSig/modifiedSig x (1 lopckBreakStrength/baseSig/100) + ti.radarLockbreakFactor = (ti.radarBaseSignature / ti.radarModifiedSignature) * (1 - (vesseljammer.lockBreakStrength / ti.radarBaseSignature / 100)); + } + + return ti.radarModifiedSignature; + } + + /// + /// Get vessel chaff factor + /// + public static float GetVesselChaffFactor(Vessel v) + { + float chaffFactor = 1.0f; + + // read vessel ecminfo for active lockbreaking jammers + VesselChaffInfo vci = v.gameObject.GetComponent(); + + if (vci) + { + // lockbreaking strength relative to jammer's lockbreak strength in relation to vessel rcs signature: + // lockbreak_factor = baseSig/modifiedSig x (1 lopckBreakStrength/baseSig/100) + chaffFactor = vci.GetChaffMultiplier(); + } + + return chaffFactor; + } + + /// + /// Get a vessel ecm jamming area (in m) where radar display garbling occurs + /// + public static float GetVesselECMJammingDistance(Vessel v) + { + float jammingDistance = 0f; + + if (v == null) + return jammingDistance; + + jammingDistance = GetVesselRadarCrossSection(v).radarJammingDistance; + + return jammingDistance; + } + + /// + /// Internal method: do the actual radar snapshot rendering from 3 sides and store it in a vesseltargetinfo attached to the vessel + /// + /// Note: Transform t is passed separatedly (instead of using v.transform), as the method need to be called from the editor + /// and there we dont have a VESSEL, only a SHIPCONSTRUCT, so the EditorRcSWindow passes the transform separately. + /// + /// when true, we try to make the rendered vessel fill the rendertexture completely, for a better detailed view. This does skew the computed cross section, so it is only for a good visual in editor! + public static float RenderVesselRadarSnapshot(Vessel v, Transform t, bool inEditorZoom = false) + { + const float radarDistance = 1000f; + const float radarFOV = 2.0f; + Vector3 presentationPosition = -t.forward * radarDistance; + + SetupResources(); + + //move vessel up for clear rendering shot (only if outside editor and thus vessel is a real vessel) + if (HighLogic.LoadedSceneIsFlight) + v.SetPosition(v.transform.position + presentationPosition); + + Bounds vesselbounds = CalcVesselBounds(v, t); + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + if (HighLogic.LoadedSceneIsFlight) + Debug.Log($"[BDArmory]: Rendering radar snapshot of vessel {v.name}, type {v.vesselType}"); + else + Debug.Log("[BDArmory]: Rendering radar snapshot of vessel"); + Debug.Log("[BDArmory]: - bounds: " + vesselbounds.ToString()); + //Debug.Log("[BDArmory]: - size: " + vesselbounds.size + ", magnitude: " + vesselbounds.size.magnitude); + } + + if (vesselbounds.size.sqrMagnitude == 0f) + { + // SAVE US THE RENDERING, result will be zero anyway... + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: - rcs is zero."); + } + + // revert presentation (only if outside editor and thus vessel is a real vessel) + if (HighLogic.LoadedSceneIsFlight) + v.SetPosition(v.transform.position - presentationPosition); + + return 0f; + } + + // pass1: frontal + RenderSinglePass(t, inEditorZoom, t.up, vesselbounds, radarDistance, radarFOV, rcsRenderingFrontal, drawTextureFrontal); + // pass2: lateral + RenderSinglePass(t, inEditorZoom, t.right, vesselbounds, radarDistance, radarFOV, rcsRenderingLateral, drawTextureLateral); + // pass3: Ventral + RenderSinglePass(t, inEditorZoom, t.forward, vesselbounds, radarDistance, radarFOV, rcsRenderingVentral, drawTextureVentral); + + //additional 45 offset renderings: + RenderSinglePass(t, inEditorZoom, (t.up + t.right), vesselbounds, radarDistance, radarFOV, rcsRenderingFrontal, drawTextureFrontal45); + RenderSinglePass(t, inEditorZoom, (t.right + t.forward), vesselbounds, radarDistance, radarFOV, rcsRenderingLateral, drawTextureLateral45); + RenderSinglePass(t, inEditorZoom, (t.forward - t.up), vesselbounds, radarDistance, radarFOV, rcsRenderingVentral, drawTextureVentral45); + + // revert presentation (only if outside editor and thus vessel is a real vessel) + if (HighLogic.LoadedSceneIsFlight) + v.SetPosition(v.transform.position - presentationPosition); + + // Count pixel colors to determine radar returns (only for normal non-zoomed rendering!) + if (!inEditorZoom) + { + rcsFrontal = 0; + rcsLateral = 0; + rcsVentral = 0; + rcsFrontal45 = 0; + rcsLateral45 = 0; + rcsVentral45 = 0; + + for (int x = 0; x < radarResolution; x++) + { + for (int y = 0; y < radarResolution; y++) + { + rcsFrontal += drawTextureFrontal.GetPixel(x, y).maxColorComponent; + rcsLateral += drawTextureLateral.GetPixel(x, y).maxColorComponent; + rcsVentral += drawTextureVentral.GetPixel(x, y).maxColorComponent; + + rcsFrontal45 += drawTextureFrontal45.GetPixel(x, y).maxColorComponent; + rcsLateral45 += drawTextureLateral45.GetPixel(x, y).maxColorComponent; + rcsVentral45 += drawTextureVentral45.GetPixel(x, y).maxColorComponent; + } + } + + // normalize rcs value, so that the structural 1x1 panel facing the radar exactly gives a return of 1 m^2: + rcsFrontal /= RCS_NORMALIZATION_FACTOR; + rcsLateral /= RCS_NORMALIZATION_FACTOR; + rcsVentral /= RCS_NORMALIZATION_FACTOR; + + rcsFrontal45 /= RCS_NORMALIZATION_FACTOR; + rcsLateral45 /= RCS_NORMALIZATION_FACTOR; + rcsVentral45 /= RCS_NORMALIZATION_FACTOR; + + rcsTotal = (Mathf.Max(rcsFrontal, rcsFrontal45) + Mathf.Max(rcsLateral, rcsLateral45) + Mathf.Max(rcsVentral, rcsVentral45)) / 3f; + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log($"[BDArmory]: - Vessel rcs is (frontal/lateral/ventral), (frontal45/lateral45/ventral45): {rcsFrontal}/{rcsLateral}/{rcsVentral}, {rcsFrontal45}/{rcsLateral45}/{rcsVentral45} = rcsTotal: {rcsTotal}"); + } + } + + return rcsTotal; + } + + /// + /// Internal helpder method + /// + private static void RenderSinglePass(Transform t, bool inEditorZoom, Vector3 cameraDirection, Bounds vesselbounds, float radarDistance, float radarFOV, RenderTexture rcsRendering, Texture2D rcsTexture) + { + // Render one snapshop pass: + // setup camera FOV + radarCam.transform.position = vesselbounds.center + cameraDirection * radarDistance; + radarCam.transform.LookAt(vesselbounds.center, -t.forward); + float distanceToShip = Vector3.Distance(radarCam.transform.position, vesselbounds.center); + radarCam.nearClipPlane = distanceToShip - 200; + radarCam.farClipPlane = distanceToShip + 200; + if (inEditorZoom) + radarCam.fieldOfView = Mathf.Atan(vesselbounds.size.magnitude / distanceToShip) * 180 / Mathf.PI; + else + radarCam.fieldOfView = radarFOV; + // setup rendertexture + radarCam.targetTexture = rcsRendering; + RenderTexture.active = rcsRendering; + Shader.SetGlobalVector("_LIGHTDIR", -cameraDirection); + Shader.SetGlobalColor("_RCSCOLOR", Color.white); + radarCam.RenderWithShader(BDAShaderLoader.RCSShader, string.Empty); + rcsTexture.ReadPixels(new Rect(0, 0, radarResolution, radarResolution), 0, 0); + rcsTexture.Apply(); + } + + /// + /// Internal method: get a vessel's bounds + /// Method implemention adapted from kronal vessel viewer + /// + private static Bounds CalcVesselBounds(Vessel v, Transform t) + { + Bounds result = new Bounds(t.position, Vector3.zero); + + List.Enumerator vp = v.Parts.GetEnumerator(); + while (vp.MoveNext()) + { + if (vp.Current.collider && !vp.Current.Modules.Contains("LaunchClamp")) + { + result.Encapsulate(vp.Current.collider.bounds); + } + } + vp.Dispose(); + + return result; + } + + /// + /// Internal method: get a vessel's size (based on it's bounds) + /// Method implemention adapted from kronal vessel viewer + /// + private static Vector3 GetVesselSize(Vessel v, Transform t) + { + return CalcVesselBounds(v, t).size; + } + + /// + /// Initialization of required resources. Necessary once per scene. + /// + public static void SetupResources() + { + if (!rcsSetupCompleted) + { + //set up rendertargets and textures + rcsRenderingFrontal = new RenderTexture(radarResolution, radarResolution, 16); + rcsRenderingLateral = new RenderTexture(radarResolution, radarResolution, 16); + rcsRenderingVentral = new RenderTexture(radarResolution, radarResolution, 16); + drawTextureFrontal = new Texture2D(radarResolution, radarResolution, TextureFormat.RGB24, false); + drawTextureLateral = new Texture2D(radarResolution, radarResolution, TextureFormat.RGB24, false); + drawTextureVentral = new Texture2D(radarResolution, radarResolution, TextureFormat.RGB24, false); + drawTextureFrontal45 = new Texture2D(radarResolution, radarResolution, TextureFormat.RGB24, false); + drawTextureLateral45 = new Texture2D(radarResolution, radarResolution, TextureFormat.RGB24, false); + drawTextureVentral45 = new Texture2D(radarResolution, radarResolution, TextureFormat.RGB24, false); + + rcsSetupCompleted = true; + } + + if (radarCam == null) + { + //set up camera + radarCam = (new GameObject("RadarCamera")).AddComponent(); + radarCam.enabled = false; + radarCam.clearFlags = CameraClearFlags.SolidColor; + radarCam.backgroundColor = Color.black; + radarCam.cullingMask = 1 << 0; // only layer 0 active, see: http://wiki.kerbalspaceprogram.com/wiki/API:Layers + } + } + + /// + /// Release of acquired resources. Necessary once at end of scene. + /// + public static void CleanupResources() + { + if (rcsSetupCompleted) + { + RenderTexture.Destroy(rcsRenderingFrontal); + RenderTexture.Destroy(rcsRenderingLateral); + RenderTexture.Destroy(rcsRenderingVentral); + Texture2D.Destroy(drawTextureFrontal); + Texture2D.Destroy(drawTextureLateral); + Texture2D.Destroy(drawTextureVentral); + Texture2D.Destroy(drawTextureFrontal45); + Texture2D.Destroy(drawTextureLateral45); + Texture2D.Destroy(drawTextureVentral45); + GameObject.Destroy(radarCam); + rcsSetupCompleted = false; + } + } + + /// + /// Determine for a vesselposition relative to the radar position how much effect the ground clutter factor will have. + /// + public static float GetRadarGroundClutterModifier(ModuleRadar radar, Transform referenceTransform, Vector3 position, Vector3 vesselposition, TargetInfo ti) + { + Vector3 upVector = referenceTransform.up; + + //ground clutter factor when looking down: + Vector3 targetDirection = (vesselposition - position); + float angleFromUp = Vector3.Angle(targetDirection, upVector); + float lookDownAngle = angleFromUp - 90; // result range: -90 .. +90 + Mathf.Clamp(lookDownAngle, 0, 90); // result range: 0 .. +90 + + float groundClutterMutiplier = Mathf.Lerp(1, radar.radarGroundClutterFactor, (lookDownAngle / 90)); + + //additional ground clutter factor when target is landed/splashed: + if (ti.isLandedOrSurfaceSplashed || ti.isSplashed) + groundClutterMutiplier *= radar.radarGroundClutterFactor; + + return groundClutterMutiplier; + } + + /// + /// Special scanning method that needs to be set manually on the radar: perform fixed boresight scan with locked fov. + /// Called from ModuleRadar, which will then attempt to immediately lock onto the detected targets. + /// Uses detectionCurve for rcs evaluation. + /// + //was: public static void UpdateRadarLock(Ray ray, float fov, float minSignature, ref TargetSignatureData[] dataArray, float dataPersistTime, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType, bool radarSnapshot) + public static bool RadarUpdateScanBoresight(Ray ray, float fov, ref TargetSignatureData[] dataArray, float dataPersistTime, ModuleRadar radar) + { + int dataIndex = 0; + bool hasLocked = false; + + // guard clauses + if (!radar) + return false; + + List.Enumerator loadedvessels = BDATargetManager.LoadedVessels.GetEnumerator(); + while (loadedvessels.MoveNext()) + { + // ignore null, unloaded + if (loadedvessels.Current == null) continue; + if (!loadedvessels.Current.loaded) continue; + + // ignore self, ignore behind ray + Vector3 vectorToTarget = (loadedvessels.Current.transform.position - ray.origin); + if (((vectorToTarget).sqrMagnitude < RADAR_IGNORE_DISTANCE_SQR) || + (Vector3.Dot(vectorToTarget, ray.direction) < 0)) + continue; + + if (Vector3.Angle(loadedvessels.Current.CoM - ray.origin, ray.direction) < fov / 2f) + { + // ignore when blocked by terrain + if (TerrainCheck(ray.origin, loadedvessels.Current.transform.position)) + continue; + + // get vessel's radar signature + TargetInfo ti = GetVesselRadarSignature(loadedvessels.Current); + float signature = ti.radarModifiedSignature; + signature *= GetRadarGroundClutterModifier(radar, radar.referenceTransform, ray.origin, loadedvessels.Current.CoM, ti); + // no ecm lockbreak factor here + // no chaff factor here + + // evaluate range + float distance = (loadedvessels.Current.CoM - ray.origin).magnitude / 1000f; //TODO: Performance! better if we could switch to sqrMagnitude... + if (distance > radar.radarMinDistanceDetect && distance < radar.radarMaxDistanceDetect) + { + //evaluate if we can detect such a signature at that range + float minDetectSig = radar.radarDetectionCurve.Evaluate(distance); + + if (signature > minDetectSig) + { + // detected by radar + // fill attempted locks array for locking later: + while (dataIndex < dataArray.Length - 1) + { + if (!dataArray[dataIndex].exists || (dataArray[dataIndex].exists && (Time.time - dataArray[dataIndex].timeAcquired) > dataPersistTime)) + { + break; + } + dataIndex++; + } + + if (dataIndex < dataArray.Length) + { + dataArray[dataIndex] = new TargetSignatureData(loadedvessels.Current, signature); + dataIndex++; + hasLocked = true; + } + } + } + + // our radar ping can be received at a higher range than we can detect, according to RWR range ping factor: + if (distance < radar.radarMaxDistanceDetect * RWR_PING_RANGE_FACTOR) + RadarWarningReceiver.PingRWR(loadedvessels.Current, ray.origin, radar.rwrType, radar.signalPersistTimeForRwr); + } + } + loadedvessels.Dispose(); + + return hasLocked; + } + + /// + /// Special scanning method for missiles with active radar homing. + /// Called from MissileBase / MissileLauncher, which will then attempt to immediately lock onto the detected targets. + /// Uses the missiles locktrackCurve for rcs evaluation. + /// + //was: UpdateRadarLock(ray, maxOffBoresight, activeRadarMinThresh, ref scannedTargets, 0.4f, true, RadarWarningReceiver.RWRThreatTypes.MissileLock, true); + public static bool RadarUpdateMissileLock(Ray ray, float fov, ref TargetSignatureData[] dataArray, float dataPersistTime, MissileBase missile) + { + int dataIndex = 0; + bool hasLocked = false; + + // guard clauses + if (!missile) + return false; + + List.Enumerator loadedvessels = BDATargetManager.LoadedVessels.GetEnumerator(); + while (loadedvessels.MoveNext()) + { + // ignore null, unloaded + if (loadedvessels.Current == null) continue; + if (!loadedvessels.Current.loaded) continue; + + // IFF code check to prevent friendly lock-on (neutral vessel without a weaponmanager WILL be lockable!) + MissileFire wm = loadedvessels.Current.FindPartModuleImplementing(); + if (wm != null) + { + if (missile.Team.IsFriendly(wm.Team)) + continue; + } + + // ignore self, ignore behind ray + Vector3 vectorToTarget = (loadedvessels.Current.transform.position - ray.origin); + if (((vectorToTarget).sqrMagnitude < RADAR_IGNORE_DISTANCE_SQR) || + (Vector3.Dot(vectorToTarget, ray.direction) < 0)) + continue; + + if (Vector3.Angle(loadedvessels.Current.CoM - ray.origin, ray.direction) < fov / 2f) + { + // ignore when blocked by terrain + if (TerrainCheck(ray.origin, loadedvessels.Current.transform.position)) + continue; + + // get vessel's radar signature + TargetInfo ti = GetVesselRadarSignature(loadedvessels.Current); + float signature = ti.radarModifiedSignature; + // no ground clutter modifier for missiles + signature *= ti.radarLockbreakFactor; //multiply lockbreak factor from active ecm + //do not multiply chaff factor here + + // evaluate range + float distance = (loadedvessels.Current.CoM - ray.origin).magnitude; //TODO: Performance! better if we could switch to sqrMagnitude... + if (distance < missile.activeRadarRange) + { + //evaluate if we can detect such a signature at that range + float minDetectSig = missile.activeRadarLockTrackCurve.Evaluate(distance / 1000f); + + if (signature > minDetectSig) + { + // detected by radar + // fill attempted locks array for locking later: + while (dataIndex < dataArray.Length - 1) + { + if (!dataArray[dataIndex].exists || (dataArray[dataIndex].exists && (Time.time - dataArray[dataIndex].timeAcquired) > dataPersistTime)) + { + break; + } + dataIndex++; + } + + if (dataIndex < dataArray.Length) + { + dataArray[dataIndex] = new TargetSignatureData(loadedvessels.Current, signature); + dataIndex++; + hasLocked = true; + } + } + } + + // our radar ping can be received at a higher range than we can detect, according to RWR range ping factor: + if (distance < missile.activeRadarRange * RWR_PING_RANGE_FACTOR) + { + if (missile.GetWeaponClass() == WeaponClasses.SLW) + RadarWarningReceiver.PingRWR(loadedvessels.Current, ray.origin, RadarWarningReceiver.RWRThreatTypes.TorpedoLock, ACTIVE_MISSILE_PING_PERISTS_TIME); + else + RadarWarningReceiver.PingRWR(loadedvessels.Current, ray.origin, RadarWarningReceiver.RWRThreatTypes.MissileLock, ACTIVE_MISSILE_PING_PERISTS_TIME); + } + } + } + loadedvessels.Dispose(); + + return hasLocked; + } + + /// + /// Main scanning and locking method called from ModuleRadar. + /// scanning both for omnidirectional and boresight scans. + /// Uses detectionCurve OR locktrackCurve for rcs evaluation, depending on wether modeTryLock is true or false. + /// + /// true: track/lock target; false: scan only + /// relevant only for modeTryLock=true + /// optional, relevant only for modeTryLock=true + /// + public static bool RadarUpdateScanLock(MissileFire myWpnManager, float directionAngle, Transform referenceTransform, float fov, Vector3 position, ModuleRadar radar, bool modeTryLock, ref TargetSignatureData[] dataArray, float dataPersistTime = 0f) + { + Vector3 forwardVector = referenceTransform.forward; + Vector3 upVector = referenceTransform.up; + Vector3 lookDirection = Quaternion.AngleAxis(directionAngle, upVector) * forwardVector; + int dataIndex = 0; + bool hasLocked = false; + + // guard clauses + if (!myWpnManager || !myWpnManager.vessel || !radar) + return false; + + List.Enumerator loadedvessels = BDATargetManager.LoadedVessels.GetEnumerator(); + while (loadedvessels.MoveNext()) + { + // ignore null, unloaded and self + if (loadedvessels.Current == null) continue; + if (!loadedvessels.Current.loaded) continue; + if (loadedvessels.Current == myWpnManager.vessel) continue; + + // ignore too close ones + if ((loadedvessels.Current.transform.position - position).sqrMagnitude < RADAR_IGNORE_DISTANCE_SQR) + continue; + + Vector3 vesselDirection = Vector3.ProjectOnPlane(loadedvessels.Current.CoM - position, upVector); + if (Vector3.Angle(vesselDirection, lookDirection) < fov / 2f) + { + // ignore when blocked by terrain + if (TerrainCheck(referenceTransform.position, loadedvessels.Current.transform.position)) + continue; + + // get vessel's radar signature + TargetInfo ti = GetVesselRadarSignature(loadedvessels.Current); + float signature = ti.radarModifiedSignature; + //do not multiply chaff factor here + signature *= GetRadarGroundClutterModifier(radar, referenceTransform, position, loadedvessels.Current.CoM, ti); + + // evaluate range + float distance = (loadedvessels.Current.CoM - position).magnitude / 1000f; //TODO: Performance! better if we could switch to sqrMagnitude... + + if (modeTryLock) // LOCK/TRACK TARGET: + { + //evaluate if we can lock/track such a signature at that range + if (distance > radar.radarMinDistanceLockTrack && distance < radar.radarMaxDistanceLockTrack) + { + //evaluate if we can lock/track such a signature at that range + float minLockSig = radar.radarLockTrackCurve.Evaluate(distance); + signature *= ti.radarLockbreakFactor; //multiply lockbreak factor from active ecm + //do not multiply chaff factor here + + if (signature > minLockSig) + { + // detected by radar + if (myWpnManager != null) + { + BDATargetManager.ReportVessel(loadedvessels.Current, myWpnManager); + } + + // fill attempted locks array for locking later: + while (dataIndex < dataArray.Length - 1) + { + if (!dataArray[dataIndex].exists || (dataArray[dataIndex].exists && (Time.time - dataArray[dataIndex].timeAcquired) > dataPersistTime)) + { + break; + } + dataIndex++; + } + + if (dataIndex < dataArray.Length) + { + dataArray[dataIndex] = new TargetSignatureData(loadedvessels.Current, signature); + dataIndex++; + hasLocked = true; + } + } + } + + // our radar ping can be received at a higher range than we can lock/track, according to RWR range ping factor: + if (distance < radar.radarMaxDistanceLockTrack * RWR_PING_RANGE_FACTOR) + RadarWarningReceiver.PingRWR(loadedvessels.Current, position, radar.rwrType, radar.signalPersistTimeForRwr); + } + else // SCAN/DETECT TARGETS: + { + //evaluate if we can detect such a signature at that range + if (distance > radar.radarMinDistanceDetect && distance < radar.radarMaxDistanceDetect) + { + //evaluate if we can detect or lock such a signature at that range + float minDetectSig = radar.radarDetectionCurve.Evaluate(distance); + //do not consider lockbreak factor from active ecm here! + //do not consider chaff here + + if (signature > minDetectSig) + { + // detected by radar + if (myWpnManager != null) + { + BDATargetManager.ReportVessel(loadedvessels.Current, myWpnManager); + } + + // report scanned targets only + radar.ReceiveContactData(new TargetSignatureData(loadedvessels.Current, signature), false); + } + } + + // our radar ping can be received at a higher range than we can detect, according to RWR range ping factor: + if (distance < radar.radarMaxDistanceDetect * RWR_PING_RANGE_FACTOR) + RadarWarningReceiver.PingRWR(loadedvessels.Current, position, radar.rwrType, radar.signalPersistTimeForRwr); + } + } + } + loadedvessels.Dispose(); + + return hasLocked; + } + + /// + /// Update a lock on a tracked target. + /// Uses locktrackCurve for rcs evaluation. + /// + //was: public static void UpdateRadarLock(Ray ray, Vector3 predictedPos, float fov, float minSignature, ModuleRadar radar, bool pingRWR, bool radarSnapshot, float dataPersistTime, bool locked, int lockIndex, Vessel lockedVessel) + public static bool RadarUpdateLockTrack(Ray ray, Vector3 predictedPos, float fov, ModuleRadar radar, float dataPersistTime, bool locked, int lockIndex, Vessel lockedVessel) + { + float closestSqrDist = 1000f; + + // guard clauses + if (!radar) + return false; + + // first: re-acquire lock if temporarily lost + if (!lockedVessel) + { + List.Enumerator loadedvessels = BDATargetManager.LoadedVessels.GetEnumerator(); + while (loadedvessels.MoveNext()) + { + // ignore null, unloaded + if (loadedvessels.Current == null) continue; + if (!loadedvessels.Current.loaded) continue; + + // ignore self, ignore behind ray + Vector3 vectorToTarget = (loadedvessels.Current.transform.position - ray.origin); + if (((vectorToTarget).sqrMagnitude < RADAR_IGNORE_DISTANCE_SQR) || + (Vector3.Dot(vectorToTarget, ray.direction) < 0)) + continue; + + if (Vector3.Angle(loadedvessels.Current.CoM - ray.origin, ray.direction) < fov / 2) + { + float sqrDist = Vector3.SqrMagnitude(loadedvessels.Current.CoM - predictedPos); + if (sqrDist < closestSqrDist) + { + // best candidate so far, take it + closestSqrDist = sqrDist; + lockedVessel = loadedvessels.Current; + } + } + } + loadedvessels.Dispose(); + } + + // second: track that lock + if (lockedVessel) + { + // blocked by terrain? + if (TerrainCheck(ray.origin, lockedVessel.transform.position)) + { + radar.UnlockTargetAt(lockIndex, true); + return false; + } + + // get vessel's radar signature + TargetInfo ti = GetVesselRadarSignature(lockedVessel); + float signature = ti.radarModifiedSignature; + signature *= GetRadarGroundClutterModifier(radar, radar.referenceTransform, ray.origin, lockedVessel.CoM, ti); + signature *= ti.radarLockbreakFactor; //multiply lockbreak factor from active ecm + //do not multiply chaff factor here + + // evaluate range + float distance = (lockedVessel.CoM - ray.origin).magnitude / 1000f; //TODO: Performance! better if we could switch to sqrMagnitude... + if (distance > radar.radarMinDistanceLockTrack && distance < radar.radarMaxDistanceLockTrack) + { + //evaluate if we can detect such a signature at that range + float minTrackSig = radar.radarLockTrackCurve.Evaluate(distance); + + if (signature > minTrackSig) + { + // can be tracked + radar.ReceiveContactData(new TargetSignatureData(lockedVessel, signature), locked); + } + else + { + // cannot track, so unlock it + radar.UnlockTargetAt(lockIndex, true); + return false; + } + } + + // our radar ping can be received at a higher range than we can detect, according to RWR range ping factor: + if (distance < radar.radarMaxDistanceLockTrack * RWR_PING_RANGE_FACTOR) + RadarWarningReceiver.PingRWR(lockedVessel, ray.origin, radar.rwrType, ACTIVE_MISSILE_PING_PERISTS_TIME); + + return true; + } + else + { + // nothing tracked/locked at this index + radar.UnlockTargetAt(lockIndex, true); + } + + return false; + } + + /// + /// Scans for targets in direction with field of view. + /// (Visual Target acquisition) + /// + public static ViewScanResults GuardScanInDirection(MissileFire myWpnManager, Transform referenceTransform, float fov, float maxDistance) + { + fov *= 1.1f; + var results = new ViewScanResults + { + foundMissile = false, + foundHeatMissile = false, + foundRadarMissile = false, + foundAGM = false, + firingAtMe = false, + missileThreatDistance = float.MaxValue, + threatVessel = null, + threatWeaponManager = null + }; + + if (!myWpnManager || !referenceTransform) + { + return results; + } + + Vector3 position = referenceTransform.position; + //Vector3d geoPos = VectorUtils.WorldPositionToGeoCoords(position, FlightGlobals.currentMainBody); + Vector3 forwardVector = referenceTransform.forward; + Vector3 upVector = referenceTransform.up; + Vector3 lookDirection = -forwardVector; + + List.Enumerator loadedvessels = BDATargetManager.LoadedVessels.GetEnumerator(); + while (loadedvessels.MoveNext()) + { + if (loadedvessels.Current == null) continue; + + if (loadedvessels.Current.loaded) + { + if (loadedvessels.Current == myWpnManager.vessel) continue; //ignore self + + Vector3 vesselProjectedDirection = Vector3.ProjectOnPlane(loadedvessels.Current.transform.position - position, upVector); + Vector3 vesselDirection = loadedvessels.Current.transform.position - position; + + float vesselDistance = (loadedvessels.Current.transform.position - position).sqrMagnitude; + if (vesselDistance < maxDistance * maxDistance && Vector3.Angle(vesselProjectedDirection, lookDirection) < fov / 2 && Vector3.Angle(loadedvessels.Current.transform.position - position, -myWpnManager.transform.forward) < myWpnManager.guardAngle / 2) + { + //Debug.Log("Found vessel: " + vessel.vesselName); + if (TerrainCheck(referenceTransform.position, loadedvessels.Current.transform.position)) + continue; //blocked by terrain + + BDATargetManager.ReportVessel(loadedvessels.Current, myWpnManager); + + vesselDistance = Mathf.Sqrt(vesselDistance); + Vector3 predictedRelativeDirection = loadedvessels.Current.transform.position - myWpnManager.vessel.PredictPosition(vesselDistance / (950 + Vector3.Dot(myWpnManager.vessel.Velocity(), vesselDirection.normalized))); + + TargetInfo tInfo; + if ((tInfo = loadedvessels.Current.gameObject.GetComponent())) + { + if (tInfo.isMissile) + { + MissileBase missileBase; + if (missileBase = tInfo.MissileBaseModule) + { + results.foundMissile = true; + results.threatVessel = missileBase.vessel; + Vector3 vectorFromMissile = myWpnManager.vessel.CoM - missileBase.part.transform.position; + Vector3 relV = missileBase.vessel.Velocity() - myWpnManager.vessel.Velocity(); + bool approaching = Vector3.Dot(relV, vectorFromMissile) > 0; + if (missileBase.HasFired && missileBase.TimeIndex > 1 && approaching && (missileBase.TargetPosition - (myWpnManager.vessel.CoM + (myWpnManager.vessel.Velocity() * Time.fixedDeltaTime))).sqrMagnitude < 3600) + { + if (missileBase.TargetingMode == MissileBase.TargetingModes.Heat) + { + results.foundHeatMissile = true; + results.missileThreatDistance = Mathf.Min(results.missileThreatDistance, Vector3.Distance(missileBase.part.transform.position, myWpnManager.part.transform.position)); + results.threatPosition = missileBase.transform.position; + break; + } + else if (missileBase.TargetingMode == MissileBase.TargetingModes.Radar) + { + results.foundRadarMissile = true; + results.missileThreatDistance = Mathf.Min(results.missileThreatDistance, Vector3.Distance(missileBase.part.transform.position, myWpnManager.part.transform.position)); + results.threatPosition = missileBase.transform.position; + } + else if (missileBase.TargetingMode == MissileBase.TargetingModes.Laser) + { + results.foundAGM = true; + results.missileThreatDistance = Mathf.Min(results.missileThreatDistance, Vector3.Distance(missileBase.part.transform.position, myWpnManager.part.transform.position)); + break; + } + } + else + { + break; + } + } + } + else + { + List.Enumerator weapon = loadedvessels.Current.FindPartModulesImplementing().GetEnumerator(); + while (weapon.MoveNext()) + { + if (!weapon.Current.recentlyFiring) continue; + if (Vector3.Dot(weapon.Current.fireTransforms[0].forward, vesselDirection) > 0) continue; + + if ((Vector3.Angle(weapon.Current.fireTransforms[0].forward, -predictedRelativeDirection) < 6500 / vesselDistance) + && (!results.firingAtMe || (weapon.Current.vessel.ReferenceTransform.position - position).sqrMagnitude < (results.threatPosition - position).sqrMagnitude)) + { + results.firingAtMe = true; + results.threatPosition = weapon.Current.vessel.transform.position; + results.threatVessel = weapon.Current.vessel; + results.threatWeaponManager = weapon.Current.weaponManager; + break; + } + } + } + } + } + } + } + + loadedvessels.Dispose(); + return results; + } + + /// + /// Helper method: check if line intersects terrain + /// + public static bool TerrainCheck(Vector3 start, Vector3 end) + { + if (!BDArmorySettings.IGNORE_TERRAIN_CHECK) + { + return Physics.Linecast(start, end, 1 << 15); + } + + return false; + } + + /// + /// Helper method: map a position onto the radar display + /// + public static Vector2 WorldToRadar(Vector3 worldPosition, Transform referenceTransform, Rect radarRect, float maxDistance) + { + float scale = maxDistance / (radarRect.height / 2); + Vector3 localPosition = referenceTransform.InverseTransformPoint(worldPosition); + localPosition.y = 0; + Vector2 radarPos = new Vector2((radarRect.width / 2) + (localPosition.x / scale), ((radarRect.height / 2) - (localPosition.z / scale))); + return radarPos; + } + + /// + /// Helper method: map a position onto the radar display (for non-onmi radars) + /// + public static Vector2 WorldToRadarRadial(Vector3 worldPosition, Transform referenceTransform, Rect radarRect, float maxDistance, float maxAngle) + { + if (referenceTransform == null) return new Vector2(); + + float scale = maxDistance / (radarRect.height); + Vector3 localPosition = referenceTransform.InverseTransformPoint(worldPosition); + localPosition.y = 0; + float angle = Vector3.Angle(localPosition, Vector3.forward); + if (localPosition.x < 0) angle = -angle; + float xPos = (radarRect.width / 2) + ((angle / maxAngle) * radarRect.width / 2); + float yPos = radarRect.height - (new Vector2(localPosition.x, localPosition.z)).magnitude / scale; + Vector2 radarPos = new Vector2(xPos, yPos); + return radarPos; + } + } +} diff --git a/BDArmory/Radar/VesselRadarData.cs b/BDArmory/Radar/VesselRadarData.cs new file mode 100644 index 000000000..04f011de1 --- /dev/null +++ b/BDArmory/Radar/VesselRadarData.cs @@ -0,0 +1,2155 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Core; +using BDArmory.Misc; +using BDArmory.Modules; +using BDArmory.Targeting; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Radar +{ + public class VesselRadarData : MonoBehaviour + { + private List availableRadars; + private List externalRadars; + private List externalVRDs; + private float _maxRadarRange = 0; + internal bool resizingWindow = false; + + public Rect RADARresizeRect = new Rect( + BDArmorySetup.WindowRectRadar.width - (17 * BDArmorySettings.RADAR_WINDOW_SCALE), + BDArmorySetup.WindowRectRadar.height - (17 * BDArmorySettings.RADAR_WINDOW_SCALE), + (16 * BDArmorySettings.RADAR_WINDOW_SCALE), + (16 * BDArmorySettings.RADAR_WINDOW_SCALE)); + + private int rCount; + + public int radarCount + { + get { return rCount; } + } + + public bool guiEnabled + { + get { return drawGUI; } + } + + private bool drawGUI; + + public MissileFire weaponManager; + public bool canReceiveRadarData; + + //GUI + public bool linkWindowOpen; + private float numberOfAvailableLinks; + public Rect linkWindowRect = new Rect(0, 0, 0, 0); + private float linkRectWidth = 200; + private float linkRectEntryHeight = 26; + + public static bool radarRectInitialized; + internal static float RadarScreenSize = 360; + internal static Rect RadarDisplayRect; + + internal static float BorderSize = 10; + internal static float HeaderSize = 15; + internal static float ControlsWidth = 125; + internal static float Gap = 2; + + private Vector2 pingSize = new Vector2(16, 8); + + private static readonly Texture2D rollIndicatorTexture = + GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "radarRollIndicator", false); + + internal static readonly Texture2D omniBgTexture = + GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "omniRadarTexture", false); + + internal static readonly Texture2D radialBgTexture = GameDatabase.Instance.GetTexture( + BDArmorySetup.textureDir + "radialRadarTexture", false); + + private static readonly Texture2D scanTexture = GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "omniRadarScanTexture", + false); + + private static readonly Texture2D lockIcon = GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "lockedRadarIcon", false); + + private static readonly Texture2D lockIconActive = + GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "lockedRadarIconActive", false); + + private static readonly Texture2D radarContactIcon = GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "radarContactIcon", + false); + + private static readonly Texture2D friendlyContactIcon = + GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "friendlyContactIcon", false); + + private GUIStyle distanceStyle; + private GUIStyle lockStyle; + private GUIStyle radarTopStyle; + + private bool noData; + + private float guiInputTime; + private float guiInputCooldown = 0.2f; + + //range increments + //TODO: Determine how to dynamically generate this list from the radar being used. + public float[] baseIncrements = new float[] { 500, 2500, 5000, 10000, 20000, 40000, 100000, 250000, 500000, 750000, 1000000, 2000000 }; + + public float[] rIncrements = new float[] { 500, 2500, 5000, 10000, 20000, 40000, 100000, 250000, 500000, 750000, 1000000, 2000000 }; + private int rangeIndex = 0; + + //lock cursor + private bool showSelector; + private Vector2 selectorPos = Vector2.zero; + + //data link + private List availableExternalVRDs; + + private Transform referenceTransform; + private Transform vesselReferenceTransform; + + public MissileBase LastMissile; + + //bool boresightScan = false; + + //TargetSignatureData[] contacts = new TargetSignatureData[30]; + private List displayedTargets; + public bool locked; + private int activeLockedTargetIndex; + private List lockedTargetIndexes; + + public bool hasLoadedExternalVRDs = false; + + public List GetLockedTargets() + { + List lockedTargets = new List(); + for (int i = 0; i < lockedTargetIndexes.Count; i++) + { + lockedTargets.Add(displayedTargets[lockedTargetIndexes[i]].targetData); + } + return lockedTargets; + } + + public RadarDisplayData lockedTargetData + { + get { return displayedTargets[lockedTargetIndexes[activeLockedTargetIndex]]; } + } + + //turret slaving + public bool slaveTurrets; + + private Vessel myVessel; + + public Vessel vessel + { + get { return myVessel; } + } + + public void AddRadar(ModuleRadar mr) + { + if (availableRadars.Contains(mr)) + { + return; + } + + availableRadars.Add(mr); + rCount = availableRadars.Count; + //UpdateDataLinkCapability(); + linkCapabilityDirty = true; + rangeCapabilityDirty = true; + } + + public void RemoveRadar(ModuleRadar mr) + { + availableRadars.Remove(mr); + rCount = availableRadars.Count; + RemoveDataFromRadar(mr); + //UpdateDataLinkCapability(); + linkCapabilityDirty = true; + rangeCapabilityDirty = true; + } + + public bool linkCapabilityDirty; + public bool rangeCapabilityDirty; + public bool radarsReady; + + private void Awake() + { + availableRadars = new List(); + externalRadars = new List(); + myVessel = GetComponent(); + lockedTargetIndexes = new List(); + availableExternalVRDs = new List(); + + distanceStyle = new GUIStyle + { + normal = { textColor = new Color(0, 1, 0, 0.75f) }, + alignment = TextAnchor.UpperLeft + }; + + lockStyle = new GUIStyle + { + normal = { textColor = new Color(0, 1, 0, 0.75f) }, + alignment = TextAnchor.LowerCenter, + fontSize = 16 + }; + + radarTopStyle = new GUIStyle + { + normal = { textColor = new Color(0, 1, 0, 0.65f) }, + alignment = TextAnchor.UpperCenter, + fontSize = 12 + }; + + vesselReferenceTransform = (new GameObject()).transform; + //vesselReferenceTransform.parent = vessel.transform; + //vesselReferenceTransform.localPosition = Vector3.zero; + vesselReferenceTransform.localScale = Vector3.one; + + displayedTargets = new List(); + externalVRDs = new List(); + waitingForVessels = new List(); + + RadarDisplayRect = new Rect(BorderSize / 2, BorderSize / 2 + HeaderSize, + RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE, + RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE); + + if (!radarRectInitialized) + { + float width = RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE + BorderSize + ControlsWidth + Gap * 3; + float height = RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE + BorderSize + HeaderSize; + BDArmorySetup.WindowRectRadar = new Rect(Screen.width - width, Screen.height - height, width, height); + radarRectInitialized = true; + } + } + + private void Start() + { + rangeIndex = rIncrements.Length - 6; + + //determine configured physics ranges and add a radar range level for the highest range + if (vessel.vesselRanges.flying.load > rIncrements[rIncrements.Length - 1]) + { + rIncrements = new[] { 500, 2500, 5000, 10000, 20000, 40000, 100000, 250000, 500000, 750000, 1000000, vessel.vesselRanges.flying.load }; + rangeIndex--; + } + + UpdateLockedTargets(); + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + mf.Current.vesselRadarData = this; + } + mf.Dispose(); + GameEvents.onVesselDestroy.Add(OnVesselDestroyed); + GameEvents.onVesselCreate.Add(OnVesselDestroyed); + MissileFire.OnChangeTeam += OnChangeTeam; + GameEvents.onGameStateSave.Add(OnGameStateSave); + GameEvents.onPartDestroyed.Add(PartDestroyed); + + if (!weaponManager) + { + List.Enumerator mfa = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mfa.MoveNext()) + { + if (mfa.Current == null) continue; + weaponManager = mfa.Current; + break; + } + mfa.Dispose(); + } + + StartCoroutine(StartupRoutine()); + } + + private IEnumerator StartupRoutine() + { + while (!FlightGlobals.ready || vessel.packed) + { + yield return null; + } + + yield return new WaitForFixedUpdate(); + yield return new WaitForFixedUpdate(); + radarsReady = true; + } + + private void OnGameStateSave(ConfigNode n) + { + SaveExternalVRDVessels(); + } + + private void SaveExternalVRDVessels() + { + string linkedVesselID = ""; + + List.Enumerator v = externalVRDs.GetEnumerator(); + while (v.MoveNext()) + { + if (v.Current == null) continue; + linkedVesselID += v.Current.vessel.id + ","; + } + v.Dispose(); + + List.Enumerator id = waitingForVessels.GetEnumerator(); + while (id.MoveNext()) + { + if (id.Current == null) continue; + linkedVesselID += id.Current + ","; + } + id.Dispose(); + + List.Enumerator radar = availableRadars.GetEnumerator(); + while (radar.MoveNext()) + { + if (radar.Current == null) continue; + if (radar.Current.vessel != vessel) continue; + radar.Current.linkedVesselID = linkedVesselID; + return; + } + radar.Dispose(); + } + + private void OnDestroy() + { + GameEvents.onVesselDestroy.Remove(OnVesselDestroyed); + GameEvents.onVesselCreate.Remove(OnVesselDestroyed); + MissileFire.OnChangeTeam -= OnChangeTeam; + GameEvents.onGameStateSave.Remove(OnGameStateSave); + GameEvents.onPartDestroyed.Remove(PartDestroyed); + + if (weaponManager) + { + if (slaveTurrets) + { + weaponManager.slavingTurrets = false; + } + } + } + + private void OnChangeTeam(MissileFire wm, BDTeam team) + { + if (!weaponManager || !wm) return; + + if (team != weaponManager.Team) + { + if (wm.vesselRadarData) + { + UnlinkVRD(wm.vesselRadarData); + } + } + else if (wm.vessel == vessel) + { + UnlinkAllExternalRadars(); + } + + RemoveDisconnectedRadars(); + } + + private void UpdateRangeCapability() + { + _maxRadarRange = 0; + List.Enumerator rad = availableRadars.GetEnumerator(); + while (rad.MoveNext()) + { + if (rad.Current == null) continue; + float maxRange = rad.Current.radarDetectionCurve.maxTime * 1000; + if (rad.Current.vessel != vessel || !(maxRange > 0)) continue; + if (maxRange > _maxRadarRange) _maxRadarRange = maxRange; + } + rad.Dispose(); + // Now rebuild range display array + List newArray = new List(); + for (int x = 0; x < baseIncrements.Length; x++) + { + newArray.Add(baseIncrements[x]); + if (_maxRadarRange <= baseIncrements[x]) + { + break; + } + } + if (newArray.Count > 0) rIncrements = newArray.ToArray(); + } + + private void UpdateDataLinkCapability() + { + canReceiveRadarData = false; + noData = true; + List.Enumerator rad = availableRadars.GetEnumerator(); + while (rad.MoveNext()) + { + if (rad.Current == null) continue; + if (rad.Current.vessel == vessel && rad.Current.canRecieveRadarData) + { + canReceiveRadarData = true; + } + + if (rad.Current.canScan) + { + noData = false; + } + } + rad.Dispose(); + + if (!canReceiveRadarData) + { + UnlinkAllExternalRadars(); + } + + List.Enumerator mr = availableRadars.GetEnumerator(); + while (mr.MoveNext()) + { + if (mr.Current == null) continue; + if (mr.Current.canScan) + { + noData = false; + } + } + mr.Dispose(); + } + + private void UpdateReferenceTransform() + { + if (radarCount == 1 && !availableRadars[0].omnidirectional && !vessel.Landed) + { + referenceTransform = availableRadars[0].referenceTransform; + } + else + { + referenceTransform = vesselReferenceTransform; + } + } + + private void PartDestroyed(Part p) + { + RemoveDisconnectedRadars(); + UpdateLockedTargets(); + RefreshAvailableLinks(); + } + + private void OnVesselDestroyed(Vessel v) + { + RemoveDisconnectedRadars(); + UpdateLockedTargets(); + RefreshAvailableLinks(); + } + + private void RemoveDisconnectedRadars() + { + availableRadars.RemoveAll(r => r == null); + List radarsToRemove = new List(); + List.Enumerator radar = availableRadars.GetEnumerator(); + while (radar.MoveNext()) + { + if (radar.Current == null) continue; + if (!radar.Current.radarEnabled || (radar.Current.vessel != vessel && !externalRadars.Contains(radar.Current))) + { + radarsToRemove.Add(radar.Current); + } + else if (!radar.Current.weaponManager || (weaponManager && radar.Current.weaponManager.Team != weaponManager.Team)) + { + radarsToRemove.Add(radar.Current); + } + } + radar.Dispose(); + + List.Enumerator rrad = radarsToRemove.GetEnumerator(); + while (rrad.MoveNext()) + { + if (rrad.Current == null) continue; + RemoveRadar(rrad.Current); + } + rrad.Dispose(); + rCount = availableRadars.Count; + + RemoveEmptyVRDs(); + } + + public void UpdateLockedTargets() + { + locked = false; + + lockedTargetIndexes.Clear(); // = new List(); + + for (int i = 0; i < displayedTargets.Count; i++) + { + if (!displayedTargets[i].vessel || !displayedTargets[i].locked) continue; + locked = true; + lockedTargetIndexes.Add(i); + } + + activeLockedTargetIndex = locked + ? Mathf.Clamp(activeLockedTargetIndex, 0, lockedTargetIndexes.Count - 1) + : 0; + } + + private void UpdateSlaveData() + { + if (!slaveTurrets || !weaponManager) return; + weaponManager.slavingTurrets = true; + if (!locked) return; + TargetSignatureData lockedTarget = lockedTargetData.targetData; + weaponManager.slavedPosition = lockedTarget.predictedPosition; + weaponManager.slavedVelocity = lockedTarget.velocity; + weaponManager.slavedAcceleration = lockedTarget.acceleration; + weaponManager.slavedTarget = lockedTarget; + } + + private void Update() + { + if (!vessel) + { + Destroy(this); + return; + } + + UpdateReferenceTransform(); + + if (radarCount > 0) + { + //vesselReferenceTransform.parent = linkedRadars[0].transform; + vesselReferenceTransform.localScale = Vector3.one; + vesselReferenceTransform.position = vessel.CoM; + + vesselReferenceTransform.rotation = Quaternion.LookRotation(vessel.LandedOrSplashed ? + VectorUtils.GetNorthVector(vessel.transform.position, vessel.mainBody) : + Vector3.ProjectOnPlane(vessel.transform.up, vessel.upAxis), vessel.upAxis); + + CleanDisplayedContacts(); + + UpdateInputs(); + + UpdateSlaveData(); + } + else + { + if (slaveTurrets) + { + UnslaveTurrets(); + } + } + + if (linkCapabilityDirty) + { + UpdateDataLinkCapability(); + linkCapabilityDirty = false; + } + + if (rangeCapabilityDirty) + { + UpdateRangeCapability(); + rangeCapabilityDirty = false; + } + + drawGUI = (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && rCount > 0 && + vessel.isActiveVessel && BDArmorySetup.GAME_UI_ENABLED && !MapView.MapIsEnabled); + + if (!vessel.loaded && radarCount == 0) + { + Destroy(this); + } + } + + public bool autoCycleLockOnFire = true; + + public void CycleActiveLock() + { + if (!locked) return; + activeLockedTargetIndex++; + if (activeLockedTargetIndex >= lockedTargetIndexes.Count) + { + activeLockedTargetIndex = 0; + } + + lockedTargetData.detectedByRadar.SetActiveLock(lockedTargetData.targetData); + + UpdateLockedTargets(); + } + + private void IncreaseRange() + { + int origIndex = rangeIndex; + rangeIndex = Mathf.Clamp(rangeIndex + 1, 0, rIncrements.Length - 1); + if (origIndex == rangeIndex) return; + pingPositionsDirty = true; + UpdateRWRRange(); + } + + private void DecreaseRange() + { + int origIndex = rangeIndex; + rangeIndex = Mathf.Clamp(rangeIndex - 1, 0, rIncrements.Length - 1); + if (origIndex == rangeIndex) return; + pingPositionsDirty = true; + UpdateRWRRange(); + } + + /// + /// Update the radar range also on the rwr display + /// + private void UpdateRWRRange() + { + List.Enumerator rwr = vessel.FindPartModulesImplementing().GetEnumerator(); + while (rwr.MoveNext()) + { + if (rwr.Current == null) continue; + rwr.Current.rwrDisplayRange = rIncrements[rangeIndex]; + } + rwr.Dispose(); + } + + private bool TryLockTarget(RadarDisplayData radarTarget) + { + if (radarTarget.locked) return false; + + ModuleRadar lockingRadar = null; + //first try using the last radar to detect that target + if (CheckRadarForLock(radarTarget.detectedByRadar, radarTarget)) + { + lockingRadar = radarTarget.detectedByRadar; + } + else + { + List.Enumerator radar = availableRadars.GetEnumerator(); + while (radar.MoveNext()) + { + if (radar.Current == null) continue; + if (!CheckRadarForLock(radar.Current, radarTarget)) continue; + lockingRadar = radar.Current; + break; + } + radar.Dispose(); + } + + if (lockingRadar != null) + { + return lockingRadar.TryLockTarget(radarTarget.targetData.predictedPosition); + } + + UpdateLockedTargets(); + StartCoroutine(UpdateLocksAfterFrame()); + return false; + } + + private IEnumerator UpdateLocksAfterFrame() + { + yield return null; + UpdateLockedTargets(); + } + + public void TryLockTarget(Vector3 worldPosition) + { + List.Enumerator displayData = displayedTargets.GetEnumerator(); + while (displayData.MoveNext()) + { + if (!(Vector3.SqrMagnitude(worldPosition - displayData.Current.targetData.predictedPosition) < + 40 * 40)) continue; + TryLockTarget(displayData.Current); + return; + } + displayData.Dispose(); + return; + } + + public bool TryLockTarget(Vessel v) + { + if (!v) return false; + + List.Enumerator displayData = displayedTargets.GetEnumerator(); + while (displayData.MoveNext()) + { + if (v == displayData.Current.vessel) + { + return TryLockTarget(displayData.Current); + } + } + displayData.Dispose(); + + RadarDisplayData newData = new RadarDisplayData + { + vessel = v, + detectedByRadar = null, + targetData = new TargetSignatureData(v, 999) + }; + + return TryLockTarget(newData); + + //return false; + } + + private bool CheckRadarForLock(ModuleRadar radar, RadarDisplayData radarTarget) + { + if (!radar) return false; + + return + ( + radar.canLock + && (!radar.locked || radar.currentLocks < radar.maxLocks) + && radarTarget.targetData.signalStrength > radar.radarLockTrackCurve.Evaluate((radarTarget.targetData.predictedPosition - radar.transform.position).magnitude / 1000f) + && + (radar.omnidirectional || + Vector3.Angle(radar.transform.up, radarTarget.targetData.predictedPosition - radar.transform.position) < + radar.directionalFieldOfView / 2) + ); + } + + private void DisableAllRadars() + { + //rCount = 0; + UnlinkAllExternalRadars(); + + List.Enumerator radar = vessel.FindPartModulesImplementing().GetEnumerator(); + while (radar.MoveNext()) + { + if (radar.Current == null) continue; + radar.Current.DisableRadar(); + } + radar.Dispose(); + } + + public void SlaveTurrets() + { + List.Enumerator mtc = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + if (mtc.Current == null) continue; + mtc.Current.slaveTurrets = false; + } + mtc.Dispose(); + slaveTurrets = true; + } + + public void UnslaveTurrets() + { + List.Enumerator mtc = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mtc.MoveNext()) + { + if (mtc.Current == null) continue; + mtc.Current.slaveTurrets = false; + } + mtc.Dispose(); + + slaveTurrets = false; + + if (weaponManager) + { + weaponManager.slavingTurrets = false; + } + } + + private void OnGUI() + { + if (!drawGUI) return; + + for (int i = 0; i < lockedTargetIndexes.Count; i++) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + string label = string.Empty; + if (i == activeLockedTargetIndex) + { + label += "Active: "; + } + if (!displayedTargets[lockedTargetIndexes[i]].vessel) + { + label += "data with no vessel"; + } + else + { + label += displayedTargets[lockedTargetIndexes[i]].vessel.vesselName; + } + GUI.Label(new Rect(20, 60 + (i * 26), 800, 446), label); + } + + TargetSignatureData lockedTarget = displayedTargets[lockedTargetIndexes[i]].targetData; + if (i == activeLockedTargetIndex) + { + if (weaponManager && weaponManager.Team.IsFriendly(lockedTarget.Team)) + { + BDGUIUtils.DrawTextureOnWorldPos(lockedTarget.predictedPosition, + BDArmorySetup.Instance.crossedGreenSquare, new Vector2(20, 20), 0); + } + else + { + BDGUIUtils.DrawTextureOnWorldPos(lockedTarget.predictedPosition, + BDArmorySetup.Instance.openGreenSquare, new Vector2(20, 20), 0); + } + } + else + { + BDGUIUtils.DrawTextureOnWorldPos(lockedTarget.predictedPosition, + BDArmorySetup.Instance.greenDiamondTexture, new Vector2(17, 17), 0); + } + } + + if (Event.current.type == EventType.MouseUp && resizingWindow) + { + resizingWindow = false; + } + const string windowTitle = "Radar"; + BDArmorySetup.WindowRectRadar = GUI.Window(524141, BDArmorySetup.WindowRectRadar, WindowRadar, windowTitle, GUI.skin.window); + BDGUIUtils.UseMouseEventInRect(BDArmorySetup.WindowRectRadar); + + if (linkWindowOpen && canReceiveRadarData) + { + linkWindowRect = new Rect(BDArmorySetup.WindowRectRadar.x - linkRectWidth, BDArmorySetup.WindowRectRadar.y + 16, linkRectWidth, + 16 + (numberOfAvailableLinks * linkRectEntryHeight)); + LinkRadarWindow(); + + BDGUIUtils.UseMouseEventInRect(linkWindowRect); + } + } + + //GUI + //============================================= + private void WindowRadar(int windowID) + { + GUI.DragWindow(new Rect(0, 0, BDArmorySetup.WindowRectRadar.width - 18, 30)); + if (GUI.Button(new Rect(BDArmorySetup.WindowRectRadar.width - 18, 2, 16, 16), "X", GUI.skin.button)) + { + DisableAllRadars(); + return; + } + if (!referenceTransform) return; + + //============================== + GUI.BeginGroup(RadarDisplayRect); + + if (availableRadars.Count == 0) return; + //bool omnidirectionalDisplay = (radarCount == 1 && linkedRadars[0].omnidirectional); + float directionalFieldOfView = omniDisplay ? 0 : availableRadars[0].directionalFieldOfView; + //bool linked = (radarCount > 1); + Rect scanRect = new Rect(0, 0, RadarDisplayRect.width, RadarDisplayRect.height); + if (omniDisplay) + { + GUI.DrawTexture(scanRect, omniBgTexture, ScaleMode.StretchToFill, true); + + if (vessel.LandedOrSplashed) + { + GUI.Label(RadarDisplayRect, " N", radarTopStyle); + } + + // Range Display and control + DisplayRange(); + + //my ship direction icon + float directionSize = 16; + Vector3 projectedVesselFwd = Vector3.ProjectOnPlane(vessel.ReferenceTransform.up, referenceTransform.up); + float dAngle = Vector3.Angle(projectedVesselFwd, referenceTransform.forward); + if (referenceTransform.InverseTransformVector(vessel.ReferenceTransform.up).x < 0) + { + dAngle = -dAngle; + } + GUIUtility.RotateAroundPivot(dAngle, scanRect.center); + GUI.DrawTexture( + new Rect(scanRect.center.x - (directionSize / 2), scanRect.center.y - (directionSize / 2), + directionSize, directionSize), BDArmorySetup.Instance.directionTriangleIcon, + ScaleMode.StretchToFill, true); + GUI.matrix = Matrix4x4.identity; + + for (int i = 0; i < rCount; i++) + { + bool canScan = availableRadars[i].canScan; + bool canTrackWhileScan = availableRadars[i].canTrackWhileScan; + bool islocked = availableRadars[i].locked; + float currentAngle = availableRadars[i].currentAngle; + + float radarAngle = VectorUtils.SignedAngle(projectedVesselFwd, + Vector3.ProjectOnPlane(availableRadars[i].transform.up, referenceTransform.up), + referenceTransform.right); + + if (!canScan || availableRadars[i].vessel != vessel) continue; + if ((!islocked || canTrackWhileScan)) + { + if (!availableRadars[i].omnidirectional) + { + currentAngle += radarAngle + dAngle; + } + else if (!vessel.Landed) + { + Vector3 north = VectorUtils.GetNorthVector(referenceTransform.position, vessel.mainBody); + float angleFromNorth = VectorUtils.SignedAngle(north, projectedVesselFwd, + Vector3.Cross(north, vessel.upAxis)); + currentAngle += angleFromNorth; + } + + GUIUtility.RotateAroundPivot(currentAngle, new Vector2((RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE) / 2, (RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE) / 2)); + if (availableRadars[i].omnidirectional && radarCount == 1) + { + GUI.DrawTexture(scanRect, scanTexture, ScaleMode.StretchToFill, true); + } + else + { + BDGUIUtils.DrawRectangle( + new Rect(scanRect.x + (scanRect.width / 2) - 1, scanRect.y, 2, scanRect.height / 2), + new Color(0, 1, 0, 0.35f)); + } + GUI.matrix = Matrix4x4.identity; + } + + //if linked and directional, draw FOV lines + if (availableRadars[i].omnidirectional) continue; + float fovAngle = availableRadars[i].directionalFieldOfView / 2; + float lineWidth = 2; + Rect verticalLineRect = new Rect(scanRect.center.x - (lineWidth / 2), 0, lineWidth, + scanRect.center.y); + GUIUtility.RotateAroundPivot(dAngle + fovAngle + radarAngle, scanRect.center); + BDGUIUtils.DrawRectangle(verticalLineRect, new Color(0, 1, 0, 0.6f)); + GUI.matrix = Matrix4x4.identity; + GUIUtility.RotateAroundPivot(dAngle - fovAngle + radarAngle, scanRect.center); + BDGUIUtils.DrawRectangle(verticalLineRect, new Color(0, 1, 0, 0.4f)); + GUI.matrix = Matrix4x4.identity; + } + } + else + { + GUI.DrawTexture(scanRect, radialBgTexture, ScaleMode.StretchToFill, true); + + DisplayRange(); + + for (int i = 0; i < rCount; i++) + { + bool canScan = availableRadars[i].canScan; + bool islocked = availableRadars[i].locked; + //float lockScanAngle = linkedRadars[i].lockScanAngle; + float currentAngle = availableRadars[i].currentAngle; + if (!canScan) continue; + float indicatorAngle = currentAngle; //locked ? lockScanAngle : currentAngle; + Vector2 scanIndicatorPos = + RadarUtils.WorldToRadarRadial( + referenceTransform.position + + (Quaternion.AngleAxis(indicatorAngle, referenceTransform.up) * referenceTransform.forward), + referenceTransform, scanRect, 5000, directionalFieldOfView / 2); + GUI.DrawTexture(new Rect(scanIndicatorPos.x - 7, scanIndicatorPos.y - 10, 14, 20), + BDArmorySetup.Instance.greenDiamondTexture, ScaleMode.StretchToFill, true); + + if (!islocked || !availableRadars[i].canTrackWhileScan) continue; + Vector2 leftPos = + RadarUtils.WorldToRadarRadial( + referenceTransform.position + + (Quaternion.AngleAxis(availableRadars[i].leftLimit, referenceTransform.up) * + referenceTransform.forward), referenceTransform, scanRect, 5000, + directionalFieldOfView / 2); + Vector2 rightPos = + RadarUtils.WorldToRadarRadial( + referenceTransform.position + + (Quaternion.AngleAxis(availableRadars[i].rightLimit, referenceTransform.up) * + referenceTransform.forward), referenceTransform, scanRect, 5000, + directionalFieldOfView / 2); + float barWidth = 2; + float barHeight = 15; + Color origColor = GUI.color; + GUI.color = Color.green; + GUI.DrawTexture(new Rect(leftPos.x - barWidth, leftPos.y - barHeight, barWidth, barHeight), + Texture2D.whiteTexture, ScaleMode.StretchToFill, true); + GUI.DrawTexture(new Rect(rightPos.x, rightPos.y - barHeight, barWidth, barHeight), + Texture2D.whiteTexture, ScaleMode.StretchToFill, true); + GUI.color = origColor; + } + } + + //selector + if (showSelector) + { + float selectorSize = 18; + Rect selectorRect = new Rect(selectorPos.x - (selectorSize / 2), selectorPos.y - (selectorSize / 2), + selectorSize, selectorSize); + Rect sLeftRect = new Rect(selectorRect.x, selectorRect.y, selectorSize / 6, selectorRect.height); + Rect sRightRect = new Rect(selectorRect.x + selectorRect.width - (selectorSize / 6), selectorRect.y, + selectorSize / 6, selectorRect.height); + BDGUIUtils.DrawRectangle(sLeftRect, Color.green); + BDGUIUtils.DrawRectangle(sRightRect, Color.green); + } + + //missile data + if (LastMissile && LastMissile.TargetAcquired) + { + Rect missileDataRect = new Rect(5, scanRect.height - 65, scanRect.width - 5, 60); + string missileDataString = LastMissile.GetShortName(); + missileDataString += "\nT-" + LastMissile.TimeToImpact.ToString("0"); + + if (LastMissile.ActiveRadar && Mathf.Round(Time.time * 3) % 2 == 0) + { + missileDataString += "\nACTIVE"; + } + GUI.Label(missileDataRect, missileDataString, distanceStyle); + } + + //roll indicator + if (!vessel.Landed) + { + Vector3 localUp = vessel.ReferenceTransform.InverseTransformDirection(referenceTransform.up); + localUp = Vector3.ProjectOnPlane(localUp, Vector3.up).normalized; + float rollAngle = -Misc.Misc.SignedAngle(-Vector3.forward, localUp, Vector3.right); + GUIUtility.RotateAroundPivot(rollAngle, scanRect.center); + GUI.DrawTexture(scanRect, rollIndicatorTexture, ScaleMode.StretchToFill, true); + GUI.matrix = Matrix4x4.identity; + } + + if (noData) + { + GUI.Label(RadarDisplayRect, "NO DATA\n", lockStyle); + } + else + { + DrawDisplayedContacts(); + } + + GUI.EndGroup(); + + // Show Control Button group + DisplayRadarControls(); + + // Resizing code block. + RADARresizeRect = + new Rect(BDArmorySetup.WindowRectRadar.width - 18, BDArmorySetup.WindowRectRadar.height - 19, 16, 16); + GUI.DrawTexture(RADARresizeRect, Misc.Misc.resizeTexture, ScaleMode.StretchToFill, true); + if (Event.current.type == EventType.MouseDown && RADARresizeRect.Contains(Event.current.mousePosition)) + { + resizingWindow = true; + } + + if (Event.current.type == EventType.Repaint && resizingWindow) + { + if (Mouse.delta.x != 0 || Mouse.delta.y != 0) + { + float diff = Mouse.delta.x + Mouse.delta.y; + UpdateRadarScale(diff); + BDArmorySetup.ResizeRadarWindow(BDArmorySettings.RADAR_WINDOW_SCALE); + } + } + // End Resizing code. + + BDGUIUtils.RepositionWindow(ref BDArmorySetup.WindowRectRadar); + } + + internal static void UpdateRadarScale(float diff) + { + float scaleDiff = ((diff / (BDArmorySetup.WindowRectRadar.width + BDArmorySetup.WindowRectRadar.height)) * 100 * .01f); + BDArmorySettings.RADAR_WINDOW_SCALE += Mathf.Abs(scaleDiff) > .01f ? scaleDiff : scaleDiff > 0 ? .01f : -.01f; + BDArmorySettings.RADAR_WINDOW_SCALE = Mathf.Clamp(BDArmorySettings.RADAR_WINDOW_SCALE, + BDArmorySettings.RADAR_WINDOW_SCALE_MIN, + BDArmorySettings.RADAR_WINDOW_SCALE_MAX); + } + + private void DisplayRange() + { + // Range Display and control + if (rangeIndex >= rIncrements.Length) DecreaseRange(); + + if (GUI.Button(new Rect(5, 5, 16, 16), "-", GUI.skin.button)) + { + DecreaseRange(); + } + + GUI.Label(new Rect(25, 5, 60, 24), (rIncrements[rangeIndex] / 1000).ToString("0") + "km", distanceStyle); + if (GUI.Button(new Rect(70, 5, 16, 16), "+", GUI.skin.button)) + { + IncreaseRange(); + } + } + + private void DisplayRadarControls() + { + float buttonHeight = 25; + float line = HeaderSize + BorderSize / 2; + float startX = BorderSize + RadarDisplayRect.width; + + //Set up button positions depending on window scale. + Rect dataLinkRect = new Rect(startX, line, ControlsWidth, buttonHeight); + line += buttonHeight + Gap; + Rect lockModeCycleRect = new Rect(startX, line, ControlsWidth, buttonHeight); + line += buttonHeight + Gap; + Rect slaveRect = new Rect(startX, line, ControlsWidth, buttonHeight); + line += buttonHeight + Gap; + Rect unlockRect = new Rect(startX, line, ControlsWidth, buttonHeight); + line += buttonHeight + Gap; + Rect unlockAllRect = new Rect(startX, line, ControlsWidth, buttonHeight); + + if (canReceiveRadarData) + { + if (GUI.Button(dataLinkRect, "Data Link", linkWindowOpen ? GUI.skin.box : GUI.skin.button)) + { + if (linkWindowOpen) + { + CloseLinkRadarWindow(); + } + else + { + OpenLinkRadarWindow(); + } + } + } + else + { + Color oCol = GUI.color; + GUI.color = new Color(1, 1, 1, 0.35f); + GUI.Box(dataLinkRect, "Link N/A", GUI.skin.button); + GUI.color = oCol; + } + + if (locked) + { + if (GUI.Button(lockModeCycleRect, "Cycle Lock", GUI.skin.button)) + { + CycleActiveLock(); + } + } + else if (!omniDisplay) //SCAN MODE SELECTOR + { + if (!locked) + { + string boresightToggle = availableRadars[0].boresightScan ? "Scan" : "Boresight"; + if (GUI.Button(lockModeCycleRect, boresightToggle, GUI.skin.button)) + { + availableRadars[0].boresightScan = !availableRadars[0].boresightScan; + } + } + } + + //slave button + if (GUI.Button(slaveRect, slaveTurrets ? "Unslave Turrets" : "Slave Turrets", + slaveTurrets ? GUI.skin.box : GUI.skin.button)) + { + if (slaveTurrets) + { + UnslaveTurrets(); + } + else + { + SlaveTurrets(); + } + } + + //unlocking + if (locked) + { + if (GUI.Button(unlockRect, "Unlock", GUI.skin.button)) + { + UnlockCurrentTarget(); + } + + if (GUI.Button(unlockAllRect, "Unlock All", GUI.skin.button)) + { + UnlockAllTargets(); + } + } + } + + private void LinkRadarWindow() + { + GUI.Box(linkWindowRect, string.Empty, GUI.skin.window); + + numberOfAvailableLinks = 0; + + GUI.BeginGroup(linkWindowRect); + + if (GUI.Button(new Rect(8, 8, 100, linkRectEntryHeight), "Refresh", GUI.skin.button)) + { + RefreshAvailableLinks(); + } + numberOfAvailableLinks += 1.25f; + + List.Enumerator v = availableExternalVRDs.GetEnumerator(); + while (v.MoveNext()) + { + if (v.Current == null) continue; + if (!v.Current.vessel || !v.Current.vessel.loaded) continue; + bool linked = externalVRDs.Contains(v.Current); + GUIStyle style = linked ? BDArmorySetup.BDGuiSkin.box : GUI.skin.button; + if ( + GUI.Button( + new Rect(8, 8 + (linkRectEntryHeight * numberOfAvailableLinks), linkRectWidth - 16, + linkRectEntryHeight), v.Current.vessel.vesselName, style)) + { + if (linked) + { + //UnlinkRadar(v); + UnlinkVRD(v.Current); + } + else + { + //LinkToRadar(v); + LinkVRD(v.Current); + } + } + numberOfAvailableLinks++; + } + v.Dispose(); + + GUI.EndGroup(); + } + + public void RemoveDataFromRadar(ModuleRadar radar) + { + displayedTargets.RemoveAll(t => t.detectedByRadar == radar); + UpdateLockedTargets(); + } + + private void UnlinkVRD(VesselRadarData vrd) + { + Debug.Log("[BDArmory]: Unlinking VRD: " + vrd.vessel.vesselName); + externalVRDs.Remove(vrd); + + List radarsToUnlink = new List(); + + List.Enumerator mra = availableRadars.GetEnumerator(); + while (mra.MoveNext()) + { + if (mra.Current == null) continue; + if (mra.Current.vesselRadarData == vrd) + { + radarsToUnlink.Add(mra.Current); + } + } + mra.Dispose(); + + List.Enumerator mr = radarsToUnlink.GetEnumerator(); + while (mr.MoveNext()) + { + if (mr.Current == null) continue; + Debug.Log("[BDArmory]: - Unlinking radar: " + mr.Current.radarName); + UnlinkRadar(mr.Current); + } + mr.Dispose(); + + SaveExternalVRDVessels(); + } + + private void UnlinkRadar(ModuleRadar mr) + { + if (mr && mr.vessel) + { + RemoveRadar(mr); + externalRadars.Remove(mr); + mr.RemoveExternalVRD(this); + + bool noMoreExternalRadar = true; + List.Enumerator rad = externalRadars.GetEnumerator(); + while (rad.MoveNext()) + { + if (rad.Current == null) continue; + if (rad.Current.vessel != mr.vessel) continue; + noMoreExternalRadar = false; + break; + } + rad.Dispose(); + + if (noMoreExternalRadar) + { + externalVRDs.Remove(mr.vesselRadarData); + } + } + else + { + externalRadars.RemoveAll(r => r == null); + } + } + + private void RemoveEmptyVRDs() + { + externalVRDs.RemoveAll(vrd => vrd == null); + List vrdsToRemove = new List(); + List.Enumerator vrda = externalVRDs.GetEnumerator(); + while (vrda.MoveNext()) + { + if (vrda.Current == null) continue; + if (vrda.Current.rCount == 0) + { + vrdsToRemove.Add(vrda.Current); + } + } + vrda.Dispose(); + + List.Enumerator vrdr = vrdsToRemove.GetEnumerator(); + while (vrdr.MoveNext()) + { + if (vrdr.Current == null) continue; + externalVRDs.Remove(vrdr.Current); + } + vrdr.Dispose(); + } + + public void UnlinkDisabledRadar(ModuleRadar mr) + { + RemoveRadar(mr); + externalRadars.Remove(mr); + SaveExternalVRDVessels(); + } + + public void BeginWaitForUnloadedLinkedRadar(ModuleRadar mr, string vesselID) + { + UnlinkDisabledRadar(mr); + + if (waitingForVessels.Contains(vesselID)) + { + return; + } + + waitingForVessels.Add(vesselID); + SaveExternalVRDVessels(); + StartCoroutine(RecoverUnloadedLinkedVesselRoutine(vesselID)); + } + + private List waitingForVessels; + + private IEnumerator RecoverUnloadedLinkedVesselRoutine(string vesselID) + { + while (true) + { + List.Enumerator v = BDATargetManager.LoadedVessels.GetEnumerator(); + while (v.MoveNext()) + { + if (v.Current == null || !v.Current.loaded || v.Current == vessel) continue; + if (v.Current.id.ToString() != vesselID) continue; + VesselRadarData vrd = v.Current.gameObject.GetComponent(); + if (!vrd) continue; + waitingForVessels.Remove(vesselID); + StartCoroutine(LinkVRDWhenReady(vrd)); + yield break; + } + v.Dispose(); + + yield return new WaitForSeconds(0.5f); + } + } + + private IEnumerator LinkVRDWhenReady(VesselRadarData vrd) + { + while (!vrd.radarsReady || vrd.vessel.packed || vrd.radarCount < 1) + { + yield return null; + } + LinkVRD(vrd); + Debug.Log("[BDArmory]: Radar data link recovered: Local - " + vessel.vesselName + ", External - " + + vrd.vessel.vesselName); + } + + public void UnlinkAllExternalRadars() + { + externalRadars.RemoveAll(r => r == null); + List.Enumerator eRad = externalRadars.GetEnumerator(); + while (eRad.MoveNext()) + { + if (eRad.Current == null) continue; + eRad.Current.RemoveExternalVRD(this); + } + eRad.Dispose(); + externalRadars.Clear(); + + externalVRDs.Clear(); + + availableRadars.RemoveAll(r => r == null); + availableRadars.RemoveAll(r => r.vessel != vessel); + rCount = availableRadars.Count; + + RefreshAvailableLinks(); + } + + private void OpenLinkRadarWindow() + { + RefreshAvailableLinks(); + linkWindowOpen = true; + } + + private void CloseLinkRadarWindow() + { + linkWindowOpen = false; + } + + private void RefreshAvailableLinks() + { + if (!HighLogic.LoadedSceneIsFlight || !weaponManager || (FlightGlobals.Vessels == null) || (!FlightGlobals.ready)) + { + return; + } + + availableExternalVRDs = new List(); + List.Enumerator v = FlightGlobals.Vessels.GetEnumerator(); + while (v.MoveNext()) + { + if (v.Current == null || !v.Current.loaded || vessel == null || v.Current == vessel) continue; + + BDTeam team = null; + List.Enumerator mf = v.Current.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + team = mf.Current.Team; + break; + } + mf.Dispose(); + + if (team != weaponManager.Team) continue; + VesselRadarData vrd = v.Current.gameObject.GetComponent(); + if (vrd && vrd.radarCount > 0) + { + availableExternalVRDs.Add(vrd); + } + } + v.Dispose(); + } + + public void LinkVRD(VesselRadarData vrd) + { + if (!externalVRDs.Contains(vrd)) + { + externalVRDs.Add(vrd); + } + + List.Enumerator mr = vrd.availableRadars.GetEnumerator(); + while (mr.MoveNext()) + { + if (mr.Current == null) continue; + LinkToRadar(mr.Current); + } + mr.Dispose(); + SaveExternalVRDVessels(); + } + + public void LinkToRadar(ModuleRadar mr) + { + if (!mr) + { + return; + } + + if (externalRadars.Contains(mr)) + { + return; + } + + externalRadars.Add(mr); + AddRadar(mr); + + mr.AddExternalVRD(this); + } + + public void AddRadarContact(ModuleRadar radar, TargetSignatureData contactData, bool _locked) + { + bool addContact = true; + + RadarDisplayData rData = new RadarDisplayData(); + rData.vessel = contactData.vessel; + + if (rData.vessel == vessel) return; + + if (rData.vessel.altitude < -20 && radar.rwrThreatType != (int)RadarWarningReceiver.RWRThreatTypes.Sonar) addContact = false; // Normal Radar Should not detect Underwater vessels + if (!rData.vessel.LandedOrSplashed && radar.rwrThreatType == (int)RadarWarningReceiver.RWRThreatTypes.Sonar) addContact = false; //Sonar should not detect Aircraft + if (rData.vessel.altitude < 0 && radar.rwrThreatType == (int)RadarWarningReceiver.RWRThreatTypes.Sonar && vessel.Splashed) addContact = true; //Sonar only detects underwater vessels // Sonar should only work when in the water + if (!vessel.Splashed && radar.rwrThreatType == (int)RadarWarningReceiver.RWRThreatTypes.Sonar) addContact = false; // Sonar should only work when in the water + if (rData.vessel.Landed && radar.rwrThreatType == (int)RadarWarningReceiver.RWRThreatTypes.Sonar) addContact = false; //Sonar should not detect land vessels + + if (addContact == false) return; + + rData.signalPersistTime = radar.signalPersistTime; + rData.detectedByRadar = radar; + rData.locked = _locked; + rData.targetData = contactData; + rData.pingPosition = UpdatedPingPosition(contactData.position, radar); + + if (_locked) + { + radar.UpdateLockedTargetInfo(contactData); + } + + bool dontOverwrite = false; + + int replaceIndex = -1; + for (int i = 0; i < displayedTargets.Count; i++) + { + if (displayedTargets[i].vessel == rData.vessel) + { + if (displayedTargets[i].locked && !_locked) + { + dontOverwrite = true; + break; + } + + replaceIndex = i; + break; + } + } + + if (replaceIndex >= 0) + { + displayedTargets[replaceIndex] = rData; + //UpdateLockedTargets(); + return; + } + else if (dontOverwrite) + { + //UpdateLockedTargets(); + return; + } + else + { + displayedTargets.Add(rData); + UpdateLockedTargets(); + return; + } + } + + public void TargetNext() + { + // activeLockedTargetIndex is the index to the list of locked targets. + // It contains the index of the displayedTargets. We are really concerned with the displayed targets here, + // but we need to keep the locked targets index list current. + int displayedTargetIndex; + if (!locked) + { + // No locked targets, get the first target in the list of displayed targets. + if (displayedTargets.Count == 0) return; + displayedTargetIndex = 0; + TryLockTarget(displayedTargets[displayedTargetIndex]); + lockedTargetIndexes.Add(displayedTargetIndex); + UpdateLockedTargets(); + return; + } + // We have locked target(s) Lets see if we can select the next one in the list (if it exists) + displayedTargetIndex = lockedTargetIndexes[activeLockedTargetIndex]; + // Lets store the displayed target that is ative + ModuleRadar rad = displayedTargets[displayedTargetIndex].detectedByRadar; + if (lockedTargetIndexes.Count > 1) + { + // We have more than one locked target. Switch to the next locked target. + if (activeLockedTargetIndex < lockedTargetIndexes.Count - 1) + activeLockedTargetIndex++; + else + { + activeLockedTargetIndex = 0; + } + UpdateLockedTargets(); + } + else + { + // If we have only one target we are done. + if (displayedTargets.Count <= 1) return; + // We have more targets to work with so attempt lock on the next available displayed target. + if (displayedTargetIndex < displayedTargets.Count - 1) + { + displayedTargetIndex++; + } + else + { + displayedTargetIndex = 0; + } + + TryLockTarget(displayedTargets[displayedTargetIndex]); + if (!displayedTargets[displayedTargetIndex].detectedByRadar) return; + // We have a good lock. Lets update the indexes and locks + lockedTargetIndexes.Add(displayedTargetIndex); + rad.UnlockTargetAt(rad.currentLockIndex); + UpdateLockedTargets(); + } + } + + public void TargetPrev() + { + // activeLockedTargetIndex is the index to the list of locked targets. + // It contains the index of the displayedTargets. We are really concerned with the displayed targets here, + // but we need to keep the locked targets index list current. + int displayedTargetIndex; + if (!locked) + { + // No locked targets, get the last target in the list of displayed targets. + if (displayedTargets.Count == 0) return; + displayedTargetIndex = displayedTargets.Count - 1; + TryLockTarget(displayedTargets[displayedTargetIndex]); + lockedTargetIndexes.Add(displayedTargetIndex); + UpdateLockedTargets(); + return; + } + // We have locked target(s) Lets see if we can select the previous one in the list (if it exists) + displayedTargetIndex = lockedTargetIndexes[activeLockedTargetIndex]; + // Lets store the displayed target that is ative + ModuleRadar rad = displayedTargets[displayedTargetIndex].detectedByRadar; + if (lockedTargetIndexes.Count > 1) + { + // We have more than one locked target. switch to the previous locked target. + if (activeLockedTargetIndex > 0) + activeLockedTargetIndex--; + else + { + activeLockedTargetIndex = lockedTargetIndexes.Count - 1; + } + UpdateLockedTargets(); + } + else + { + // If we have only one target we are done. + if (displayedTargets.Count <= 1) return; + // We have more targets to work with so attempt lock on the pevious available displayed target. + if (displayedTargetIndex > 0) + { + displayedTargetIndex--; + } + else + { + displayedTargetIndex = displayedTargets.Count - 1; + } + + TryLockTarget(displayedTargets[displayedTargetIndex]); + if (!displayedTargets[displayedTargetIndex].detectedByRadar) return; + // We got a good lock. Lets update the indexes and locks + lockedTargetIndexes.Add(displayedTargetIndex); + rad.UnlockTargetAt(rad.currentLockIndex); + UpdateLockedTargets(); + } + } + + public void UnlockAllTargetsOfRadar(ModuleRadar radar) + { + //radar.UnlockTarget(); + displayedTargets.RemoveAll(t => t.detectedByRadar == radar); + UpdateLockedTargets(); + } + + public void RemoveVesselFromTargets(Vessel _vessel) + { + displayedTargets.RemoveAll(t => t.vessel == _vessel); + UpdateLockedTargets(); + } + + public void UnlockAllTargets() + { + List.Enumerator radar = weaponManager.radars.GetEnumerator(); + while (radar.MoveNext()) + { + if (radar.Current == null) continue; + radar.Current.UnlockAllTargets(); + } + radar.Dispose(); + } + + public void UnlockCurrentTarget() + { + if (!locked) return; + + ModuleRadar rad = displayedTargets[lockedTargetIndexes[activeLockedTargetIndex]].detectedByRadar; + rad.UnlockTargetAt(rad.currentLockIndex); + } + + private void CleanDisplayedContacts() + { + int count = displayedTargets.Count; + displayedTargets.RemoveAll(t => t.targetData.age > t.signalPersistTime * 2); + if (count != displayedTargets.Count) + { + UpdateLockedTargets(); + } + } + + private Vector2 UpdatedPingPosition(Vector3 worldPosition, ModuleRadar radar) + { + if (rangeIndex < 0 || rangeIndex > rIncrements.Length - 1) rangeIndex = rIncrements.Length - 1; + if (omniDisplay) + { + return RadarUtils.WorldToRadar(worldPosition, referenceTransform, RadarDisplayRect, rIncrements[rangeIndex]); + } + else + { + return RadarUtils.WorldToRadarRadial(worldPosition, referenceTransform, RadarDisplayRect, + rIncrements[rangeIndex], radar.directionalFieldOfView / 2); + } + } + + private bool pingPositionsDirty = true; + + private void DrawDisplayedContacts() + { + float myAlt = (float)vessel.altitude; + + bool drewLockLabel = false; + float lockIconSize = 24 * BDArmorySettings.RADAR_WINDOW_SCALE; + + bool lockDirty = false; + + for (int i = 0; i < displayedTargets.Count; i++) + { + if (displayedTargets[i].locked && locked) + { + TargetSignatureData lockedTarget = displayedTargets[i].targetData; + //LOCKED GUI + Vector2 pingPosition; + if (omniDisplay) + { + pingPosition = RadarUtils.WorldToRadar(lockedTarget.position, referenceTransform, RadarDisplayRect, + rIncrements[rangeIndex]); + } + else + { + pingPosition = RadarUtils.WorldToRadarRadial(lockedTarget.position, referenceTransform, + RadarDisplayRect, rIncrements[rangeIndex], + displayedTargets[i].detectedByRadar.directionalFieldOfView / 2); + } + + //BDGUIUtils.DrawRectangle(new Rect(pingPosition.x-(4),pingPosition.y-(4),8, 8), Color.green); + float vAngle = Vector3.Angle(Vector3.ProjectOnPlane(lockedTarget.velocity, referenceTransform.up), + referenceTransform.forward); + if (referenceTransform.InverseTransformVector(lockedTarget.velocity).x < 0) + { + vAngle = -vAngle; + } + GUIUtility.RotateAroundPivot(vAngle, pingPosition); + Rect pingRect = new Rect(pingPosition.x - (lockIconSize / 2), pingPosition.y - (lockIconSize / 2), + lockIconSize, lockIconSize); + + Texture2D txtr = (i == lockedTargetIndexes[activeLockedTargetIndex]) ? lockIconActive : lockIcon; + GUI.DrawTexture(pingRect, txtr, ScaleMode.StretchToFill, true); + GUI.matrix = Matrix4x4.identity; + GUI.Label(new Rect(pingPosition.x + (lockIconSize * 0.35f) + 2, pingPosition.y, 100, 24), + (lockedTarget.altitude / 1000).ToString("0"), distanceStyle); + + if (!drewLockLabel) + { + GUI.Label(RadarDisplayRect, "-LOCK-\n", lockStyle); + drewLockLabel = true; + + if (slaveTurrets) + { + GUI.Label(RadarDisplayRect, "TURRETS\n\n", lockStyle); + } + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + GUI.Label(new Rect(pingPosition.x + (pingSize.x / 2), pingPosition.y, 100, 24), + lockedTarget.signalStrength.ToString("0.0")); + } + + if (GUI.Button(pingRect, GUIContent.none, GUIStyle.none) && + Time.time - guiInputTime > guiInputCooldown) + { + guiInputTime = Time.time; + if (i == lockedTargetIndexes[activeLockedTargetIndex]) + { + //UnlockTarget(displayedTargets[i].detectedByRadar); + //displayedTargets[i].detectedByRadar.UnlockTargetAtPosition(displayedTargets[i].targetData.position); + displayedTargets[i].detectedByRadar.UnlockTargetVessel(displayedTargets[i].vessel); + UpdateLockedTargets(); + lockDirty = true; + } + else + { + for (int x = 0; x < lockedTargetIndexes.Count; x++) + { + if (i == lockedTargetIndexes[x]) + { + activeLockedTargetIndex = x; + break; + } + } + + displayedTargets[i].detectedByRadar.SetActiveLock(displayedTargets[i].targetData); + + UpdateLockedTargets(); + } + } + + //DLZ + if (!lockDirty) + { + int lTarInd = lockedTargetIndexes[activeLockedTargetIndex]; + + if (i == lTarInd && weaponManager && weaponManager.selectedWeapon != null) + { + if (weaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || weaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.SLW) + { + MissileBase currMissile = weaponManager.CurrentMissile; + if (currMissile.TargetingMode == MissileBase.TargetingModes.Radar || currMissile.TargetingMode == MissileBase.TargetingModes.Heat) + { + MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(currMissile, lockedTarget.velocity, lockedTarget.predictedPosition); + float rangeToPixels = (1 / rIncrements[rangeIndex]) * RadarDisplayRect.height; + float dlzWidth = 12; + float lineWidth = 2; + float dlzX = RadarDisplayRect.width - dlzWidth - lineWidth; + + BDGUIUtils.DrawRectangle(new Rect(dlzX, 0, dlzWidth, RadarDisplayRect.height), Color.black); + + Rect maxRangeVertLineRect = new Rect(RadarDisplayRect.width - lineWidth, + Mathf.Clamp(RadarDisplayRect.height - (dlz.maxLaunchRange * rangeToPixels), 0, + RadarDisplayRect.height), lineWidth, + Mathf.Clamp(dlz.maxLaunchRange * rangeToPixels, 0, RadarDisplayRect.height)); + BDGUIUtils.DrawRectangle(maxRangeVertLineRect, Color.green); + + Rect maxRangeTickRect = new Rect(dlzX, maxRangeVertLineRect.y, dlzWidth, lineWidth); + BDGUIUtils.DrawRectangle(maxRangeTickRect, Color.green); + + Rect minRangeTickRect = new Rect(dlzX, + Mathf.Clamp(RadarDisplayRect.height - (dlz.minLaunchRange * rangeToPixels), 0, + RadarDisplayRect.height), dlzWidth, lineWidth); + BDGUIUtils.DrawRectangle(minRangeTickRect, Color.green); + + Rect rTrTickRect = new Rect(dlzX, + Mathf.Clamp(RadarDisplayRect.height - (dlz.rangeTr * rangeToPixels), 0, RadarDisplayRect.height), + dlzWidth, lineWidth); + BDGUIUtils.DrawRectangle(rTrTickRect, Color.green); + + Rect noEscapeLineRect = new Rect(dlzX, rTrTickRect.y, lineWidth, + minRangeTickRect.y - rTrTickRect.y); + BDGUIUtils.DrawRectangle(noEscapeLineRect, Color.green); + + float targetDistIconSize = 16 * BDArmorySettings.RADAR_WINDOW_SCALE; + float targetDistY; + if (!omniDisplay) + { + targetDistY = pingPosition.y - (targetDistIconSize / 2); + } + else + { + targetDistY = RadarDisplayRect.height - + (Vector3.Distance(lockedTarget.predictedPosition, + referenceTransform.position) * rangeToPixels) - + (targetDistIconSize / 2); + } + + Rect targetDistanceRect = new Rect(dlzX - (targetDistIconSize / 2), targetDistY, + targetDistIconSize, targetDistIconSize); + GUIUtility.RotateAroundPivot(90, targetDistanceRect.center); + GUI.DrawTexture(targetDistanceRect, BDArmorySetup.Instance.directionTriangleIcon, + ScaleMode.StretchToFill, true); + GUI.matrix = Matrix4x4.identity; + } + } + } + } + } + else + { + float minusAlpha = + (Mathf.Clamp01((Time.time - displayedTargets[i].targetData.timeAcquired) / + displayedTargets[i].signalPersistTime) * 2) - 1; + + //jamming + // NEW: evaluation via radarutils! + bool jammed = false; + float distanceToTarget = (this.vessel.transform.position - displayedTargets[i].targetData.position).sqrMagnitude; + float jamDistance = RadarUtils.GetVesselECMJammingDistance(displayedTargets[i].targetData.vessel); + if (displayedTargets[i].targetData.vesselJammer && jamDistance * jamDistance > distanceToTarget) + { + jammed = true; + } + + if (pingPositionsDirty) + { + //displayedTargets[i].pingPosition = UpdatedPingPosition(displayedTargets[i].targetData.position, displayedTargets[i].detectedByRadar); + RadarDisplayData newData = new RadarDisplayData(); + newData.detectedByRadar = displayedTargets[i].detectedByRadar; + newData.locked = displayedTargets[i].locked; + newData.pingPosition = UpdatedPingPosition(displayedTargets[i].targetData.position, + displayedTargets[i].detectedByRadar); + newData.signalPersistTime = displayedTargets[i].signalPersistTime; + newData.targetData = displayedTargets[i].targetData; + newData.vessel = displayedTargets[i].vessel; + displayedTargets[i] = newData; + } + Vector2 pingPosition = displayedTargets[i].pingPosition; + + Rect pingRect; + //draw missiles and debris as dots + if ((displayedTargets[i].targetData.targetInfo && + displayedTargets[i].targetData.targetInfo.isMissile) || + displayedTargets[i].targetData.Team == null) + { + float mDotSize = 6; + pingRect = new Rect(pingPosition.x - (mDotSize / 2), pingPosition.y - (mDotSize / 2), mDotSize, + mDotSize); + Color origGUIColor = GUI.color; + GUI.color = Color.white - new Color(0, 0, 0, minusAlpha); + GUI.DrawTexture(pingRect, BDArmorySetup.Instance.greenDotTexture, ScaleMode.StretchToFill, + true); + GUI.color = origGUIColor; + } + //draw contacts with direction indicator + else if (!jammed && (displayedTargets[i].detectedByRadar.showDirectionWhileScan) && + displayedTargets[i].targetData.velocity.sqrMagnitude > 100) + { + pingRect = new Rect(pingPosition.x - (lockIconSize / 2), pingPosition.y - (lockIconSize / 2), + lockIconSize, lockIconSize); + float vAngle = + Vector3.Angle( + Vector3.ProjectOnPlane(displayedTargets[i].targetData.velocity, referenceTransform.up), + referenceTransform.forward); + if (referenceTransform.InverseTransformVector(displayedTargets[i].targetData.velocity).x < 0) + { + vAngle = -vAngle; + } + GUIUtility.RotateAroundPivot(vAngle, pingPosition); + Color origGUIColor = GUI.color; + GUI.color = Color.white - new Color(0, 0, 0, minusAlpha); + if (weaponManager && + weaponManager.Team.IsFriendly(displayedTargets[i].targetData.Team)) + { + GUI.DrawTexture(pingRect, friendlyContactIcon, ScaleMode.StretchToFill, true); + } + else + { + GUI.DrawTexture(pingRect, radarContactIcon, ScaleMode.StretchToFill, true); + } + + GUI.matrix = Matrix4x4.identity; + GUI.Label(new Rect(pingPosition.x + (lockIconSize * 0.35f) + 2, pingPosition.y, 100, 24), + (displayedTargets[i].targetData.altitude / 1000).ToString("0"), distanceStyle); + GUI.color = origGUIColor; + } + else //draw contacts as rectangles + { + int drawCount = jammed ? 4 : 1; + pingRect = new Rect(pingPosition.x - (pingSize.x / 2), pingPosition.y - (pingSize.y / 2), pingSize.x, + pingSize.y); + for (int d = 0; d < drawCount; d++) + { + Rect jammedRect = new Rect(pingRect); + Vector3 contactPosition = displayedTargets[i].targetData.position; + if (jammed) + { + //jamming + Vector3 jammedPosition = transform.position + + ((displayedTargets[i].targetData.position - transform.position) + .normalized * + Random.Range(100, rIncrements[rangeIndex])); + float bearingVariation = + Mathf.Clamp( + Mathf.Pow(32000, 2) / + (displayedTargets[i].targetData.position - transform.position).sqrMagnitude, 0, + 80); + jammedPosition = transform.position + + (Quaternion.AngleAxis( + Random.Range(-bearingVariation, bearingVariation), + referenceTransform.up) * (jammedPosition - transform.position)); + if (omniDisplay) + { + pingPosition = RadarUtils.WorldToRadar(jammedPosition, referenceTransform, RadarDisplayRect, + rIncrements[rangeIndex]); + } + else + { + pingPosition = RadarUtils.WorldToRadarRadial(jammedPosition, referenceTransform, + RadarDisplayRect, rIncrements[rangeIndex], + displayedTargets[i].detectedByRadar.directionalFieldOfView / 2); + } + + jammedRect = new Rect(pingPosition.x - (pingSize.x / 2), + pingPosition.y - (pingSize.y / 2) - (pingSize.y / 3), pingSize.x, pingSize.y / 3); + contactPosition = jammedPosition; + } + + Color iconColor = Color.green; + float contactAlt = displayedTargets[i].targetData.altitude; + if (!omniDisplay && !jammed) + { + if (contactAlt - myAlt > 1000) + { + iconColor = new Color(0, 0.6f, 1f, 1); + } + else if (contactAlt - myAlt < -1000) + { + iconColor = new Color(1f, 0.68f, 0, 1); + } + } + + if (omniDisplay) + { + Vector3 localPos = referenceTransform.InverseTransformPoint(contactPosition); + localPos.y = 0; + float angleToContact = Vector3.Angle(localPos, Vector3.forward); + if (localPos.x < 0) angleToContact = -angleToContact; + GUIUtility.RotateAroundPivot(angleToContact, pingPosition); + } + + if (jammed || + !weaponManager.Team.IsFriendly(displayedTargets[i].targetData.Team)) + { + BDGUIUtils.DrawRectangle(jammedRect, iconColor - new Color(0, 0, 0, minusAlpha)); + } + else + { + float friendlySize = 12; + Rect friendlyRect = new Rect(pingPosition.x - (friendlySize / 2), + pingPosition.y - (friendlySize / 2), friendlySize, friendlySize); + Color origGuiColor = GUI.color; + GUI.color = iconColor - new Color(0, 0, 0, minusAlpha); + GUI.DrawTexture(friendlyRect, BDArmorySetup.Instance.greenDotTexture, + ScaleMode.StretchToFill, true); + GUI.color = origGuiColor; + } + + GUI.matrix = Matrix4x4.identity; + } + } + + if (GUI.Button(pingRect, GUIContent.none, GUIStyle.none) && + Time.time - guiInputTime > guiInputCooldown) + { + guiInputTime = Time.time; + TryLockTarget(displayedTargets[i]); + } + + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + GUI.Label(new Rect(pingPosition.x + (pingSize.x / 2), pingPosition.y, 100, 24), + displayedTargets[i].targetData.signalStrength.ToString("0.0")); + } + } + } + pingPositionsDirty = false; + } + + private bool omniDisplay + { + get { return (radarCount > 1 || (radarCount == 1 && availableRadars[0].omnidirectional)); } + } + + private void UpdateInputs() + { + if (!vessel.isActiveVessel) + { + return; + } + + if (BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_RIGHT)) + { + ShowSelector(); + SlewSelector(Vector2.right); + } + else if (BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_LEFT)) + { + ShowSelector(); + SlewSelector(-Vector2.right); + } + + if (BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_UP)) + { + ShowSelector(); + SlewSelector(-Vector2.up); + } + else if (BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_DOWN)) + { + ShowSelector(); + SlewSelector(Vector2.up); + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_LOCK)) + { + if (showSelector) + { + TryLockViaSelector(); + } + ShowSelector(); + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_CYCLE_LOCK)) + { + if (locked) + { + CycleActiveLock(); + } + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_SCAN_MODE)) + { + if (!locked && radarCount > 0 && !omniDisplay) + { + availableRadars[0].boresightScan = !availableRadars[0].boresightScan; + } + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_TURRETS)) + { + if (slaveTurrets) + { + UnslaveTurrets(); + } + else + { + SlaveTurrets(); + } + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_RANGE_UP)) + { + IncreaseRange(); + } + else if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_RANGE_DN)) + { + DecreaseRange(); + } + + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_TARGET_NEXT)) + { + TargetNext(); + } + else if (BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_TARGET_PREV)) + { + TargetPrev(); + } + } + + private void TryLockViaSelector() + { + bool found = false; + Vector3 closestPos = Vector3.zero; + float closestSqrMag = float.MaxValue; + for (int i = 0; i < displayedTargets.Count; i++) + { + float sqrMag = (displayedTargets[i].pingPosition - selectorPos).sqrMagnitude; + if (sqrMag < closestSqrMag) + { + if (sqrMag < Mathf.Pow(20, 2)) + { + closestPos = displayedTargets[i].targetData.predictedPosition; + found = true; + } + } + } + + if (found) + { + TryLockTarget(closestPos); + } + else if (closestSqrMag > Mathf.Pow(40, 2)) + { + UnlockCurrentTarget(); + } + } + + private void SlewSelector(Vector2 direction) + { + float rate = 150; + selectorPos += direction * rate * Time.deltaTime; + + if (!omniDisplay) + { + if (selectorPos.y > RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE * 0.975f) + { + if (rangeIndex > 0) + { + DecreaseRange(); + selectorPos.y = RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE * 0.75f; + } + } + else if (selectorPos.y < RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE * 0.025f) + { + if (rangeIndex < rIncrements.Length - 1) + { + IncreaseRange(); + selectorPos.y = RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE * 0.25f; + } + } + } + + selectorPos.y = Mathf.Clamp(selectorPos.y, 10, RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE - 10); + selectorPos.x = Mathf.Clamp(selectorPos.x, 10, RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE - 10); + } + + private void ShowSelector() + { + if (!showSelector) + { + showSelector = true; + selectorPos = new Vector2(RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE / 2, RadarScreenSize * BDArmorySettings.RADAR_WINDOW_SCALE / 2); + } + } + } +} diff --git a/BDArmory/Shaders/BDAShaderLoader.cs b/BDArmory/Shaders/BDAShaderLoader.cs new file mode 100644 index 000000000..c180b04d1 --- /dev/null +++ b/BDArmory/Shaders/BDAShaderLoader.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.IO; +using UniLinq; +using UnityEngine; + +namespace BDArmory.Shaders +{ + [KSPAddon(KSPAddon.Startup.MainMenu, false)] + public class BDAShaderLoader : MonoBehaviour + { + private static bool _loaded; + + private static string _bundlePath; + + public static Shader GrayscaleEffectShader; + public static Shader UnlitBlackShader; + public static Shader BulletShader; + public static Shader RCSShader; + + public string BundlePath + { + get + { + switch (Application.platform) + { + case RuntimePlatform.OSXPlayer: + return _bundlePath + Path.DirectorySeparatorChar + + "bdarmoryshaders_macosx.bundle"; + + case RuntimePlatform.WindowsPlayer: + return _bundlePath + Path.DirectorySeparatorChar + + "bdarmoryshaders_windows.bundle"; + + case RuntimePlatform.LinuxPlayer: + return _bundlePath + Path.DirectorySeparatorChar + + "bdarmoryshaders_macosx.bundle"; + + default: + return _bundlePath + Path.DirectorySeparatorChar + + "bdarmoryshaders_windows.bundle"; + } + } + } + + private void Awake() + { + _bundlePath = KSPUtil.ApplicationRootPath + "GameData" + + Path.DirectorySeparatorChar + + "BDArmory" + Path.DirectorySeparatorChar + "AssetBundles"; + } + + private void Start() + { + if (!_loaded) + { + Debug.Log("[BDArmory] start bundle load process"); + //StartCoroutine(LoadBundleAssets()); + LoadBundleAssets(); + _loaded = true; + } + } + + private void LoadBundleAssets() + { + Debug.Log("[BDArmory] Loading bundle data"); + + AssetBundle shaderBundle = AssetBundle.LoadFromFile(BundlePath); + + if (shaderBundle != null) + { + Shader[] shaders = shaderBundle.LoadAllAssets(); + IEnumerator shader = shaders.AsEnumerable().GetEnumerator(); + while (shader.MoveNext()) + { + if (shader.Current == null) continue; + Debug.Log($"[BDArmory] Shader \"{shader.Current.name}\" loaded. Shader supported? {shader.Current.isSupported}"); + + switch (shader.Current.name) + { + case "BDArmory/Particles/Bullet": + BulletShader = shader.Current; + break; + + case "Custom/Unlit Black": + UnlitBlackShader = shader.Current; + break; + + case "Hidden/Grayscale Effect": + GrayscaleEffectShader = shader.Current; + break; + + case "Custom/rcsShader": + RCSShader = shader.Current; + break; + + default: + Debug.Log($"[BDArmory] Not expected shader : {shader.Current.name}"); + break; + } + } + + shader.Dispose(); + //yield return null; + Debug.Log("[BDArmory] unloading bundles"); + shaderBundle.Unload(false); // unload the raw asset bundle + } + else + { + Debug.Log("[BDArmory] Error: Found no asset bundle to load"); + } + + //yield return null; + } + } +} diff --git a/BDArmory/Shaders/BulletShader.shader b/BDArmory/Shaders/BulletShader.shader new file mode 100644 index 000000000..4a498344f --- /dev/null +++ b/BDArmory/Shaders/BulletShader.shader @@ -0,0 +1,121 @@ +Shader "BDArmory/Particles/Bullet" +{ + Properties + { + _TintColor("Tint Color", Color) = (0.5,0.5,0.5,0.5) + _MainTex("Particle Texture", 2D) = "white" {} + _InvFade("Soft Particles Factor", Range(0.01,3.0)) = 1.0 + _Lum("Luminance", float) = 1 + } + + Category + { + Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } + Blend SrcAlpha OneMinusSrcColor + AlphaTest Greater .01 + ColorMask RGB + Cull Off Lighting Off ZWrite Off Fog{ Color(0,0,0,0) } + BindChannels{ + Bind "Color", color + Bind "Vertex", vertex + Bind "TexCoord", texcoord + } + + // ---- Fragment program cards + SubShader + { + Pass + { + CGPROGRAM + #pragma target 3.5 + #pragma vertex vert + #pragma fragment frag + #pragma fragmentoption ARB_precision_hint_fastest + #pragma multi_compile_particles + + #include "UnityCG.cginc" + + sampler2D _MainTex; + float4 _TintColor; + half _Lum; + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + #ifdef SOFTPARTICLES_ON + float4 projPos : TEXCOORD1; + #endif + }; + + float4 _MainTex_ST; + + v2f vert(appdata_t v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + #ifdef SOFTPARTICLES_ON + o.projPos = ComputeScreenPos(o.vertex); + COMPUTE_EYEDEPTH(o.projPos.z); + #endif + o.color = v.color; + o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); + return o; + } + + sampler2D _CameraDepthTexture; + float _InvFade; + + half4 frag(v2f i) : COLOR + { + #ifdef SOFTPARTICLES_ON + float sceneZ = LinearEyeDepth(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)).r); + float partZ = i.projPos.z; + float fade = saturate(_InvFade * (sceneZ - partZ)); + i.color.a *= fade; + #endif + half4 prev = i.color * tex2D(_MainTex, i.texcoord) * _TintColor * _Lum * 2; + prev.rgb *= prev.a; + return prev; + } + ENDCG + } + } + + // ---- Dual texture cards + SubShader + { + Pass + { + SetTexture[_MainTex] + { + combine texture * primary + } + SetTexture[_MainTex] + { + combine previous * previous alpha, previous + } + } + } + + // ---- Single texture cards (does not do particle colors) + SubShader + { + Pass + { + SetTexture[_MainTex] + { + combine texture * texture alpha, texture + } + } + } + } +} diff --git a/BDArmory/Shaders/GrayscaleEffectShader.shader b/BDArmory/Shaders/GrayscaleEffectShader.shader new file mode 100644 index 000000000..4018f0f54 --- /dev/null +++ b/BDArmory/Shaders/GrayscaleEffectShader.shader @@ -0,0 +1,55 @@ +Shader "Hidden/Grayscale Effect" { + Properties{ + _MainTex("Base (RGB)", 2D) = "white" {} + _RampTex("Base (RGB)", 2D) = "grayscaleRamp" {} + _RedPower("Red Power", Range(0.001,1.0)) = 1.0 + _RedDelta("Red Delta", Range(0.001,1.0)) = 1.0 + } + + SubShader{ + Pass{ + ZTest Always Cull Off ZWrite Off + Fog{ Mode off } + + CGPROGRAM +#pragma target 3.5 +#pragma vertex vert_img +#pragma fragment frag +#pragma fragmentoption ARB_precision_hint_fastest +#include "UnityCG.cginc" + + uniform sampler2D _MainTex; + uniform sampler2D _RampTex; + uniform half _RampOffset; + uniform float _RedPower; + uniform float _RedDelta; + + fixed4 frag(v2f_img i) : COLOR + { + fixed4 original = tex2D(_MainTex, i.uv); + fixed grayscale = Luminance(original.rgb); + half2 remap = half2 (grayscale + _RampOffset, .5); + fixed4 output = tex2D(_RampTex, remap); + + half avg = original.r + original.g + original.b; + avg *= 0.333; + half4 nC = half4(avg,avg,avg,original.a); + + half avg2 = original.g + original.b; + avg2 *= 0.5; + + if (original.r > _RedPower && (original.r - avg2) > _RedDelta) + { + nC.rgb = half3(original.r,avg2,avg2); + } + + output = fixed4(nC.r,nC.g,nC.b,original.a); + + return output; + } + ENDCG + } + } + + Fallback off +} diff --git a/BDArmory/Shaders/UnlitBlack.shader b/BDArmory/Shaders/UnlitBlack.shader new file mode 100644 index 000000000..dd0723d8c --- /dev/null +++ b/BDArmory/Shaders/UnlitBlack.shader @@ -0,0 +1,13 @@ +Shader "Custom/Unlit Black" +{ + Properties + { + //_Color ("Color", Color) = (1,1,1) + } + + SubShader + { + Color(0,0,0)//[_Color] + Pass {} + } +} diff --git a/BDArmory/Shaders/rcsShader.shader b/BDArmory/Shaders/rcsShader.shader new file mode 100644 index 000000000..469113df1 --- /dev/null +++ b/BDArmory/Shaders/rcsShader.shader @@ -0,0 +1,65 @@ +// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' + +Shader "Custom/rcsShader" +{ + Properties + { + _RCSCOLOR("RCSCOLOR", Color) = (1, 1, 1, 1) + _LIGHTDIR("LIGHTDIR", Vector) = (0, 0, 1) + } + + SubShader + { + Pass + { + CGPROGRAM + + // DEFINES + #pragma target 3.5 + #pragma vertex RCSVertexShader + #pragma fragment RCSFragmentShader + + // INCLUDES + #include "UnityCG.cginc" + #include "UnityLightingCommon.cginc" + #include "UnityStandardBRDF.cginc" + + // uniforms from properties + float4 _RCSCOLOR; + float3 _LIGHTDIR; + + struct VertexData + { + float4 position : POSITION; + float3 normal : NORMAL; + float2 uv : TEXCOORD0; + }; + + struct Interpolators + { + float4 position : SV_POSITION; + float3 normal : TEXCOORD1; + }; + + // Main Vertex Program + Interpolators RCSVertexShader(VertexData v) + { + Interpolators i; + i.position = UnityObjectToClipPos(v.position); + i.normal = UnityObjectToWorldNormal(v.normal); + //i.uv = TRANSFORM_TEX(v.uv, _MainTex); + return i; + } + + // Main Fragment Program + float4 RCSFragmentShader(Interpolators i) : SV_TARGET + { + float3 lightDir = _WorldSpaceLightPos0.xyz; + float3 lightColor = _RCSCOLOR.rgb; + float3 reflectionDir = reflect(-_LIGHTDIR, i.normal); + return DotClamped(_LIGHTDIR, reflectionDir); + } + ENDCG + } //PASS + } //SUBSHADER +} diff --git a/BDArmory/SmartFindTarget.dgml b/BDArmory/SmartFindTarget.dgml new file mode 100644 index 000000000..48fb17c63 --- /dev/null +++ b/BDArmory/SmartFindTarget.dgml @@ -0,0 +1,634 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BDArmory/Targeting/TargetInfo.cs b/BDArmory/Targeting/TargetInfo.cs new file mode 100644 index 000000000..cc8bae2a1 --- /dev/null +++ b/BDArmory/Targeting/TargetInfo.cs @@ -0,0 +1,320 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Core.Extension; +using BDArmory.Misc; +using BDArmory.Modules; +using BDArmory.UI; +using UnityEngine; + +namespace BDArmory.Targeting +{ + public class TargetInfo : MonoBehaviour + { + public BDTeam Team; + public bool isMissile; + public MissileBase MissileBaseModule; + public MissileFire weaponManager; + Dictionary> friendliesEngaging = new Dictionary>(); + public Dictionary detectedTime = new Dictionary(); + + public float radarBaseSignature = -1; + public bool radarBaseSignatureNeedsUpdate = true; + public float radarModifiedSignature; + public float radarLockbreakFactor; + public float radarJammingDistance; + public bool alreadyScheduledRCSUpdate = false; + + public bool isLandedOrSurfaceSplashed + { + get + { + if (!vessel) return false; + if ( + (vessel.situation == Vessel.Situations.LANDED || + vessel.situation == Vessel.Situations.SPLASHED) && // Boats should be included + !isUnderwater //refrain from shooting subs with missiles + ) + { + return true; + } + else + return false; + } + } + + public bool isFlying + { + get + { + if (!vessel) return false; + if (vessel.situation == Vessel.Situations.FLYING || vessel.InOrbit()) return true; + else + return false; + } + } + + public bool isUnderwater + { + get + { + if (!vessel) return false; + if (vessel.altitude < -20) //some boats sit slightly underwater, this is only for submersibles + { + return true; + } + else + { + return false; + } + } + } + + public bool isSplashed + { + get + { + if (!vessel) return false; + if (vessel.situation == Vessel.Situations.SPLASHED) return true; + else + return false; + } + } + + public Vector3 velocity + { + get + { + if (!vessel) return Vector3.zero; + return vessel.Velocity(); + } + } + + public Vector3 position + { + get + { + return vessel.vesselTransform.position; + } + } + + private Vessel vessel; + + public Vessel Vessel + { + get + { + return vessel; + } + set + { + vessel = value; + } + } + + public bool isThreat + { + get + { + if (!Vessel) + { + return false; + } + + if (isMissile && MissileBaseModule && !MissileBaseModule.HasMissed) + { + return true; + } + else if (weaponManager && weaponManager.vessel.isCommandable) //Fix for GLOC'd pilots. IsControllable merely checks if plane has pilot; Iscommandable checks if they're conscious + { + return true; + } + + return false; + } + } + + void Awake() + { + if (!vessel) + { + vessel = GetComponent(); + } + + if (!vessel) + { + //Debug.Log ("[BDArmory]: TargetInfo was added to a non-vessel"); + Destroy(this); + return; + } + + //destroy this if a target info is already attached to the vessel + IEnumerator otherInfo = vessel.gameObject.GetComponents().GetEnumerator(); + while (otherInfo.MoveNext()) + { + if ((object)otherInfo.Current != this) + { + Destroy(this); + return; + } + } + + Team = null; + bool foundMf = false; + List.Enumerator mf = vessel.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + foundMf = true; + Team = mf.Current.Team; + weaponManager = mf.Current; + break; + } + mf.Dispose(); + + if (!foundMf) + { + List.Enumerator ml = vessel.FindPartModulesImplementing().GetEnumerator(); + while (ml.MoveNext()) + { + isMissile = true; + MissileBaseModule = ml.Current; + Team = ml.Current.Team; + break; + } + ml.Dispose(); + } + + vessel.OnJustAboutToBeDestroyed += AboutToBeDestroyed; + + //add delegate to peace enable event + BDArmorySetup.OnPeaceEnabled += OnPeaceEnabled; + + //lifeRoutine = StartCoroutine(LifetimeRoutine()); // TODO: CHECK BEHAVIOUR AND SIDE EFFECTS! + + if (!isMissile && Team != null) + { + GameEvents.onVesselPartCountChanged.Add(VesselModified); + //massRoutine = StartCoroutine(MassRoutine()); // TODO: CHECK BEHAVIOUR AND SIDE EFFECTS! + } + } + + void OnPeaceEnabled() + { + //Destroy(this); + } + + void OnDestroy() + { + //remove delegate from peace enable event + BDArmorySetup.OnPeaceEnabled -= OnPeaceEnabled; + vessel.OnJustAboutToBeDestroyed -= AboutToBeDestroyed; + GameEvents.onVesselPartCountChanged.Remove(VesselModified); + } + + IEnumerator UpdateRCSDelayed() + { + alreadyScheduledRCSUpdate = true; + yield return new WaitForSeconds(1.0f); + //radarBaseSignatureNeedsUpdate = true; //TODO: currently disabled to reduce stuttering effects due to more demanding radar rendering! + } + + void Update() + { + if (!vessel) + { + AboutToBeDestroyed(); + } + else + { + if ((vessel.vesselType == VesselType.Debris) && (weaponManager == null)) + { + BDATargetManager.RemoveTarget(this); + Team = null; + } + } + } + + public int NumFriendliesEngaging(BDTeam team) + { + if (friendliesEngaging.TryGetValue(team, out var friendlies)) + { + friendlies.RemoveAll(item => item == null); + return friendlies.Count; + } + return 0; + } + + public int TotalEngaging() + { + int engaging = 0; + using (var teamEngaging = friendliesEngaging.GetEnumerator()) + while (teamEngaging.MoveNext()) + engaging += teamEngaging.Current.Value.Count; + return engaging; + } + + public void Engage(MissileFire mf) + { + if (mf == null) + return; + + if (friendliesEngaging.TryGetValue(mf.Team, out var friendlies)) + { + if (!friendlies.Contains(mf)) + friendlies.Add(mf); + } + else + friendliesEngaging.Add(mf.Team, new List { mf }); + } + + public void Disengage(MissileFire mf) + { + if (mf == null) + return; + + if (friendliesEngaging.TryGetValue(mf.Team, out var friendlies)) + friendlies.Remove(mf); + } + + void AboutToBeDestroyed() + { + BDATargetManager.RemoveTarget(this); + Destroy(this); + } + + public bool IsCloser(TargetInfo otherTarget, MissileFire myMf) + { + float thisSqrDist = (position - myMf.transform.position).sqrMagnitude; + float otherSqrDist = (otherTarget.position - myMf.transform.position).sqrMagnitude; + return thisSqrDist < otherSqrDist; + } + + public void VesselModified(Vessel v) + { + if (v && v == this.vessel) + { + if (!alreadyScheduledRCSUpdate) + StartCoroutine(UpdateRCSDelayed()); + } + } + + public static Vector3 TargetCOMDispersion(Vessel v) + { + Vector3 TargetCOM_ = new Vector3(0, 0); + ShipConstruct sc = new ShipConstruct("ship", "temp ship", v.parts[0]); + + Vector3 size = ShipConstruction.CalculateCraftSize(sc); + + float dispersionMax = size.y; + + //float dispersionMax = 100f; + + float dispersion = Random.Range(0, dispersionMax); + + TargetCOM_ = v.CoM + new Vector3(0, dispersion); + + return TargetCOM_; + } + } +} + +; diff --git a/BDArmory/Targeting/TargetSignatureData.cs b/BDArmory/Targeting/TargetSignatureData.cs new file mode 100644 index 000000000..beb9ea96f --- /dev/null +++ b/BDArmory/Targeting/TargetSignatureData.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using BDArmory.Core.Extension; +using BDArmory.CounterMeasure; +using BDArmory.Misc; +using BDArmory.Modules; +using BDArmory.Radar; +using UnityEngine; + +namespace BDArmory.Targeting +{ + public struct TargetSignatureData : IEquatable + { + public Vector3 velocity; + public Vector3 geoPos; + public Vector3 acceleration; + public bool exists; + public float timeAcquired; + public float signalStrength; + public TargetInfo targetInfo; + public BDTeam Team; + public Vector2 pingPosition; + public VesselECMJInfo vesselJammer; + public ModuleRadar lockedByRadar; + public Vessel vessel; + bool orbital; + Orbit orbit; + + public bool Equals(TargetSignatureData other) + { + return + exists == other.exists && + geoPos == other.geoPos && + timeAcquired == other.timeAcquired; + } + + public TargetSignatureData(Vessel v, float _signalStrength) + { + orbital = v.InOrbit(); + orbit = v.orbit; + + timeAcquired = Time.time; + vessel = v; + velocity = v.Velocity(); + + geoPos = VectorUtils.WorldPositionToGeoCoords(v.CoM, v.mainBody); + acceleration = v.acceleration_immediate; + exists = true; + + signalStrength = _signalStrength; + + targetInfo = v.gameObject.GetComponent(); + + // vessel never been picked up on radar before: create new targetinfo record + if (targetInfo == null) + { + targetInfo = v.gameObject.AddComponent(); + } + + Team = null; + + if (targetInfo) // Always true, as we just set it? + { + Team = targetInfo.Team; + } + else + { + List.Enumerator mf = v.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + Team = mf.Current.Team; + break; + } + mf.Dispose(); + } + + vesselJammer = v.gameObject.GetComponent(); + + pingPosition = Vector2.zero; + lockedByRadar = null; + } + + public TargetSignatureData(CMFlare flare, float _signalStrength) + { + velocity = flare.velocity; + geoPos = VectorUtils.WorldPositionToGeoCoords(flare.transform.position, FlightGlobals.currentMainBody); + exists = true; + acceleration = Vector3.zero; + timeAcquired = Time.time; + signalStrength = _signalStrength; + targetInfo = null; + vesselJammer = null; + Team = null; + pingPosition = Vector2.zero; + orbital = false; + orbit = null; + lockedByRadar = null; + vessel = null; + } + + public TargetSignatureData(Vector3 _velocity, Vector3 _position, Vector3 _acceleration, bool _exists, float _signalStrength) + { + velocity = _velocity; + geoPos = VectorUtils.WorldPositionToGeoCoords(_position, FlightGlobals.currentMainBody); + acceleration = _acceleration; + exists = _exists; + timeAcquired = Time.time; + signalStrength = _signalStrength; + targetInfo = null; + vesselJammer = null; + Team = null; + pingPosition = Vector2.zero; + orbital = false; + orbit = null; + lockedByRadar = null; + vessel = null; + } + + public Vector3 position + { + get + { + return VectorUtils.GetWorldSurfacePostion(geoPos, FlightGlobals.currentMainBody); + } + set + { + geoPos = VectorUtils.WorldPositionToGeoCoords(value, FlightGlobals.currentMainBody); + } + } + + public Vector3 predictedPosition + { + get + { + return position + (velocity * age); + } + } + + public Vector3 predictedPositionWithChaffFactor + { + get + { + // get chaff factor of vessel and calculate decoy distortion caused by chaff echos + float decoyFactor = 0f; + Vector3 posDistortion = Vector3.zero; + + if (vessel != null) + { + // chaff check + decoyFactor = (1f - RadarUtils.GetVesselChaffFactor(vessel)); + + if (decoyFactor > 0f) + { + // with ecm on better chaff effectiveness due to higher modifiedSignature + // higher speed -> missile decoyed further "behind" where the chaff drops (also means that for head-on engagements chaff is most like less effective!) + posDistortion = (vessel.GetSrfVelocity() * -1f * Mathf.Clamp(decoyFactor * decoyFactor, 0f, 0.5f)) + (UnityEngine.Random.insideUnitSphere * UnityEngine.Random.Range(targetInfo.radarModifiedSignature, targetInfo.radarModifiedSignature * targetInfo.radarModifiedSignature) * decoyFactor); + } + } + + return position + (velocity * age) + posDistortion; + } + } + + public float altitude + { + get + { + return geoPos.z; + } + } + + public float age + { + get + { + return (Time.time - timeAcquired); + } + } + + public static TargetSignatureData noTarget + { + get + { + return new TargetSignatureData(Vector3.zero, Vector3.zero, Vector3.zero, false, 0); + } + } + + public static void ResetTSDArray(ref TargetSignatureData[] tsdArray) + { + for (int i = 0; i < tsdArray.Length; i++) + { + tsdArray[i] = noTarget; + } + } + } +} diff --git a/BDArmory/UI/BDAEditorAnalysisWindow.cs b/BDArmory/UI/BDAEditorAnalysisWindow.cs new file mode 100644 index 000000000..d80abd01b --- /dev/null +++ b/BDArmory/UI/BDAEditorAnalysisWindow.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using BDArmory.Misc; +using BDArmory.Modules; +using BDArmory.Radar; +using KSP.UI.Screens; +using UnityEngine; + +namespace BDArmory.UI +{ + [KSPAddon(KSPAddon.Startup.EditorAny, false)] + internal class BDAEditorAnalysisWindow : MonoBehaviour + { + public static BDAEditorAnalysisWindow Instance = null; + private ApplicationLauncherButton toolbarButton = null; + + private bool showRcsWindow = false; + private string windowTitle = "BDArmory Radar Cross Section Analysis"; + private Rect windowRect = new Rect(300, 150, 650, 500); + + private bool takeSnapshot = false; + private float rcsReductionFactor; + private float rcsGCF = 1.0f; + + private ModuleRadar[] radars; + private GUIContent[] radarsGUI; + private GUIContent radarBoxText; + private BDGUIComboBox radarBox; + private int previous_index = -1; + private string text_detection; + private string text_locktrack; + private string text_sonar; + private bool bLandedSplashed; + + void Awake() + { + } + + void Start() + { + Instance = this; + AddToolbarButton(); + + RadarUtils.SetupResources(); + GameEvents.onEditorShipModified.Add(OnEditorShipModifiedEvent); + } + + private void FillRadarList() + { + radars = BDAEditorTools.getRadars().ToArray(); + + // first pass, then sort + for (int i = 0; i < radars.Length; i++) + { + if (string.IsNullOrEmpty(radars[i].radarName)) radars[i].radarName = radars[i].part?.partInfo?.title; + GUIContent gui = new GUIContent(radars[i].radarName); + } + Array.Sort(radars, delegate (ModuleRadar r1, ModuleRadar r2) { return r1.radarName.CompareTo(r2.radarName); }); + + // second pass to copy + radarsGUI = new GUIContent[radars.Length]; + for (int i = 0; i < radars.Length; i++) + { + GUIContent gui = new GUIContent(radars[i].radarName); + radarsGUI[i] = gui; + } + + radarBoxText = new GUIContent(); + radarBoxText.text = "Select Radar... **"; + } + + private void OnEditorShipModifiedEvent(ShipConstruct data) + { + takeSnapshot = true; + previous_index = -1; + } + + private void OnDestroy() + { + GameEvents.onEditorShipModified.Remove(OnEditorShipModifiedEvent); + RadarUtils.CleanupResources(); + + if (toolbarButton) + { + ApplicationLauncher.Instance.RemoveModApplication(toolbarButton); + toolbarButton = null; + } + } + + IEnumerator ToolbarButtonRoutine() + { + if (toolbarButton || (!HighLogic.LoadedSceneIsEditor)) yield break; + while (!ApplicationLauncher.Ready) + { + yield return null; + } + + AddToolbarButton(); + } + + void AddToolbarButton() + { + if (HighLogic.LoadedSceneIsEditor) + { + if (toolbarButton == null) + { + Texture buttonTexture = GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "icon_rcs", false); + toolbarButton = ApplicationLauncher.Instance.AddModApplication(ShowToolbarGUI, HideToolbarGUI, Dummy, Dummy, Dummy, Dummy, ApplicationLauncher.AppScenes.SPH | ApplicationLauncher.AppScenes.VAB, buttonTexture); + } + } + } + + public void ShowToolbarGUI() + { + showRcsWindow = true; + takeSnapshot = true; + } + + public void HideToolbarGUI() + { + showRcsWindow = false; + takeSnapshot = false; + } + + void Dummy() + { } + + void OnGUI() + { + if (showRcsWindow) + { + windowRect = GUI.Window(this.GetInstanceID(), windowRect, WindowRcs, windowTitle, BDArmorySetup.BDGuiSkin.window); + } + + PreventClickThrough(); + } + + void WindowRcs(int windowID) + { + if (GUI.Button(new Rect(windowRect.width - 18, 2, 16, 16), "X")) + { + HideToolbarGUI(); + } + + GUI.Label(new Rect(10, 40, 200, 20), "Frontal", BDArmorySetup.BDGuiSkin.box); + GUI.Label(new Rect(220, 40, 200, 20), "Lateral", BDArmorySetup.BDGuiSkin.box); + GUI.Label(new Rect(430, 40, 200, 20), "Ventral", BDArmorySetup.BDGuiSkin.box); + + if (takeSnapshot) + takeRadarSnapshot(); + + // for each view draw the rendering with the higher cross section (normal or 45°): + if (RadarUtils.rcsFrontal > RadarUtils.rcsFrontal45) + GUI.DrawTexture(new Rect(10, 70, 200, 200), RadarUtils.GetTextureFrontal, ScaleMode.StretchToFill); + else + GUI.DrawTexture(new Rect(10, 70, 200, 200), RadarUtils.GetTextureFrontal45, ScaleMode.StretchToFill); + + if (RadarUtils.rcsLateral > RadarUtils.rcsLateral45) + GUI.DrawTexture(new Rect(220, 70, 200, 200), RadarUtils.GetTextureLateral, ScaleMode.StretchToFill); + else + GUI.DrawTexture(new Rect(220, 70, 200, 200), RadarUtils.GetTextureLateral45, ScaleMode.StretchToFill); + + if (RadarUtils.rcsVentral > RadarUtils.rcsVentral45) + GUI.DrawTexture(new Rect(430, 70, 200, 200), RadarUtils.GetTextureVentral, ScaleMode.StretchToFill); + else + GUI.DrawTexture(new Rect(430, 70, 200, 200), RadarUtils.GetTextureVentral45, ScaleMode.StretchToFill); + + GUI.Label(new Rect(10, 275, 200, 20), string.Format("{0:0.00}", Mathf.Max(RadarUtils.rcsFrontal, RadarUtils.rcsFrontal45)) + " m^2", BDArmorySetup.BDGuiSkin.label); + GUI.Label(new Rect(220, 275, 200, 20), string.Format("{0:0.00}", Mathf.Max(RadarUtils.rcsLateral, RadarUtils.rcsLateral45)) + " m^2", BDArmorySetup.BDGuiSkin.label); + GUI.Label(new Rect(430, 275, 200, 20), string.Format("{0:0.00}", Mathf.Max(RadarUtils.rcsVentral, RadarUtils.rcsVentral45)) + " m^2", BDArmorySetup.BDGuiSkin.label); + + GUIStyle style = BDArmorySetup.BDGuiSkin.label; + style.fontStyle = FontStyle.Bold; + GUI.Label(new Rect(10, 300, 600, 20), "Base radar cross section for vessel: " + string.Format("{0:0.00} m^2 (without ECM/countermeasures)", RadarUtils.rcsTotal), style); + GUI.Label(new Rect(10, 320, 600, 20), "Total radar cross section for vessel: " + string.Format("{0:0.00} m^2 (with RCS reduction/stealth/ground clutter)", RadarUtils.rcsTotal * rcsReductionFactor * rcsGCF), style); + + style.fontStyle = FontStyle.Normal; + GUI.Label(new Rect(10, 380, 600, 20), "** (Range evaluation not accounting for ECM/countermeasures)", style); + GUI.Label(new Rect(10, 410, 600, 20), text_detection, style); + GUI.Label(new Rect(10, 430, 600, 20), text_locktrack, style); + GUI.Label(new Rect(10, 450, 600, 20), text_sonar, style); + + bool bNewValue = GUI.Toggle(new Rect(490, 348, 150, 20), bLandedSplashed, "Splashed/Landed", BDArmorySetup.BDGuiSkin.toggle); + + if (radars == null) + { + FillRadarList(); + GUIStyle listStyle = new GUIStyle(BDArmorySetup.BDGuiSkin.button); + listStyle.fixedHeight = 18; //make list contents slightly smaller + radarBox = new BDGUIComboBox(new Rect(10, 350, 600, 20), new Rect(10, 350, 250, 20), radarBoxText, radarsGUI, 124, listStyle); + } + + int selected_index = radarBox.Show(); + + if ((selected_index != previous_index) || (bNewValue != bLandedSplashed)) + { + text_sonar = ""; + bLandedSplashed = bNewValue; + + // selected radar changed - evaluate craft RCS against this radar + if (selected_index != -1) + { + var selected_radar = radars[selected_index]; + + // ground clutter factor from radar + if (bLandedSplashed) + rcsGCF = selected_radar.radarGroundClutterFactor; + else + rcsGCF = 1.0f; + + if (selected_radar.canScan) + { + for (float distance = selected_radar.radarMaxDistanceDetect; distance >= 0; distance--) + { + text_detection = $"Detection: undetectable by this radar."; + if (selected_radar.radarDetectionCurve.Evaluate(distance) <= (RadarUtils.rcsTotal * rcsReductionFactor * rcsGCF)) + { + text_detection = $"Detection: detected at {distance} km and closer"; + break; + } + } + } + else + { + text_detection = "Detection: This radar does not have detection capabilities."; + } + + if (selected_radar.canLock) + { + text_locktrack = $"Lock/Track: untrackable by this radar."; + for (float distance = selected_radar.radarMaxDistanceLockTrack; distance >= 0; distance--) + { + if (selected_radar.radarLockTrackCurve.Evaluate(distance) <= (RadarUtils.rcsTotal * rcsReductionFactor * rcsGCF)) + { + text_locktrack = $"Lock/Track: tracked at {distance} km and closer"; + break; + } + } + } + else + { + text_locktrack = "Lock/Track: This radar does not have locking/tracking capabilities."; + } + + if (selected_radar.getRWRType(selected_radar.rwrThreatType) == "SONAR") + text_sonar = "SONAR - will only be able to detect/track splashed or submerged vessels!"; + } + } + previous_index = selected_index; + + GUI.DragWindow(); + BDGUIUtils.RepositionWindow(ref windowRect); + } + + void takeRadarSnapshot() + { + if (EditorLogic.RootPart == null) + return; + + // Encapsulate editor ShipConstruct into a vessel: + Vessel v = new Vessel(); + v.parts = EditorLogic.fetch.ship.Parts; + RadarUtils.RenderVesselRadarSnapshot(v, EditorLogic.RootPart.transform); //first rendering for true RCS + RadarUtils.RenderVesselRadarSnapshot(v, EditorLogic.RootPart.transform, true); //second rendering for nice zoomed-in view + takeSnapshot = false; + + // get RCS reduction measures (stealth/low observability) + rcsReductionFactor = 1.0f; + int rcsCount = 0; + List.Enumerator parts = EditorLogic.fetch.ship.Parts.GetEnumerator(); + while (parts.MoveNext()) + { + ModuleECMJammer rcsJammer = parts.Current.GetComponent(); + if (rcsJammer != null) + { + if (rcsJammer.rcsReduction) + { + rcsReductionFactor *= rcsJammer.rcsReductionFactor; + rcsCount++; + } + } + } + parts.Dispose(); + + if (rcsCount > 0) + rcsReductionFactor = Mathf.Clamp((rcsReductionFactor * rcsCount), 0.0f, 1); //same formula as in VesselECMJInfo must be used here! + } + + /// + /// Lock the model if our own window is shown and has cursor focus to prevent click-through. + /// Code adapted from FAR Editor GUI + /// + private void PreventClickThrough() + { + bool cursorInGUI = false; + EditorLogic EdLogInstance = EditorLogic.fetch; + if (!EdLogInstance) + { + return; + } + if (showRcsWindow) + { + cursorInGUI = windowRect.Contains(GetMousePos()); + } + if (cursorInGUI) + { + if (!CameraMouseLook.GetMouseLook()) + EdLogInstance.Lock(false, false, false, "BDARCSLOCK"); + else + EdLogInstance.Unlock("BDARCSLOCK"); + } + else if (!cursorInGUI) + { + EdLogInstance.Unlock("BDARCSLOCK"); + } + } + + private Vector3 GetMousePos() + { + Vector3 mousePos = Input.mousePosition; + mousePos.y = Screen.height - mousePos.y; + return mousePos; + } + } //EditorRCsWindow +} diff --git a/BDArmory/UI/BDAEditorCategory.cs b/BDArmory/UI/BDAEditorCategory.cs new file mode 100644 index 000000000..fa892cc9f --- /dev/null +++ b/BDArmory/UI/BDAEditorCategory.cs @@ -0,0 +1,424 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Control; +using BDArmory.Core; +using BDArmory.CounterMeasure; +using BDArmory.Modules; +using KSP.UI; +using KSP.UI.Screens; +using UnityEngine; + +namespace BDArmory.UI +{ + [KSPAddon(KSPAddon.Startup.EditorAny, false)] + public class BDAEditorCategory : MonoBehaviour + { + public static BDAEditorCategory Instance; + public PartCategorizer.Category BDACategory; + public const string BDACategoryKey = "bdacategory"; + public const string AutoBDACategoryKey = "autobdacategory"; + public const int SubcategoryGroup = 412440121; + + /// + /// Adding to this dictionary before the category buttons are created will add more bda categories. + /// + public static readonly List Categories = new List + { + "All", + "Control", + "Guns", + "Gun turrets", + "Lasers", + "Laser turrets", + "Rocket pods", + "Rocket turrets", + "Missiles", + "Missile turrets", + "Bombs", + "Torpedoes", + "Ammo", + "Radars", + "Targeting", + "Countermeasures", + "Armor", + }; + + public static readonly Dictionary CategoryIcons = new Dictionary + { + {"All", "BDArmory/Textures/Infinity"}, + {"Control", "BDArmory/Textures/Control"}, + {"Guns", "BDArmory/Textures/Gun"}, + {"Gun turrets", "BDArmory/Textures/GunTurret"}, + {"Lasers", "BDArmory/Textures/LaserIcon"}, + {"Laser turrets", "BDArmory/Textures/LaserTurret"}, + {"Rocket pods", "BDArmory/Textures/Rocket"}, + {"Rocket turrets", "BDArmory/Textures/RocketTurret"}, + {"Missiles", "BDArmory/Textures/Missile"}, + {"Missile turrets", "BDArmory/Textures/MissileTurret"}, + {"Bombs", "BDArmory/Textures/Bomb"}, + {"Torpedoes", "BDArmory/Textures/Torpedo"}, + {"Ammo", "BDArmory/Textures/Ammo"}, + {"Radars", "BDArmory/Textures/Radar"}, + {"Targeting", "BDArmory/Textures/Targeting"}, + {"Countermeasures", "BDArmory/Textures/Countermeasures"}, + {"Armor", "BDArmory/Textures/Defense"}, + {"Misc", "BDArmory/Textures/Misc"}, + {"Legacy", "BDArmory/Textures/icon"}, + }; + private List SubcategoryButtons = new List(); + private string CurrentCategory = BDArmorySettings.SHOW_CATEGORIES ? "All" : "Legacy"; + private RectTransform BDAPartBar; + private PartCategorizer.Category FilterByFunctionCategory; + private const float SettingsWidth = 230; + private const float SettingsHeight = 83; + private const float SettingsMargin = 18; + private const float SettingsLineHeight = 22; + private Rect SettingsWindow = new Rect(0, 0, SettingsWidth, SettingsHeight); + private bool expanded = false; + private bool SettingsOpen = false; + private readonly Vector3 offset = new Vector3(34, 0, 0); + + private void Awake() + { + Instance = this; + bool partsDetected = false; + using (var parts = PartLoader.LoadedPartsList.GetEnumerator()) + while (parts.MoveNext()) + { + if (parts.Current == null || !parts.Current.partPrefab || parts.Current.partConfig == null) + continue; + if (parts.Current.partConfig.HasValue(BDACategoryKey) || parts.Current.manufacturer == Misc.BDAEditorTools.Manufacturer) + { + partsDetected = true; + GameEvents.onGUIEditorToolbarReady.Add(LoadBDArmoryCategory); + break; + } + } + // Part autocategorization + if (partsDetected) + using (var parts = PartLoader.LoadedPartsList.GetEnumerator()) + while (parts.MoveNext()) + { + if (parts.Current.partConfig == null || parts.Current.partPrefab == null) + continue; + if (parts.Current.partConfig.HasValue(BDACategoryKey)) + parts.Current.partConfig.AddValue(AutoBDACategoryKey, parts.Current.partConfig.GetValue(BDACategoryKey)); + else + { + ModuleWeapon moduleWeapon; + MissileLauncher missileLauncher; + if ((moduleWeapon = parts.Current.partPrefab.FindModuleImplementing()) != null) + { + if (moduleWeapon.weaponType == "laser") + { + if (parts.Current.partPrefab.FindModuleImplementing()) + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Laser turrets"); + else + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Lasers"); + } + else + { + if (parts.Current.partPrefab.FindModuleImplementing()) + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Gun turrets"); + else + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Guns"); + } + } + else if ((missileLauncher = parts.Current.partPrefab.FindModuleImplementing()) != null) + { + // weapon class is not parsed when in editor, so using missileType + if (missileLauncher.missileType.ToLower() == "bomb") + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Bombs"); + else if (missileLauncher.missileType.ToLower() == "torpedo" || missileLauncher.missileType.ToLower() == "depthcharge") + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Torpedoes"); + else + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Missiles"); + } + else if (parts.Current.partPrefab.FindModuleImplementing() != null) + { + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Missile turrets"); + } + else if (parts.Current.partPrefab.FindModuleImplementing() != null) + { + if (parts.Current.partPrefab.FindModuleImplementing()) + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Rocket turrets"); + else + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Rocket pods"); + } + else if (parts.Current.partPrefab.FindModuleImplementing() != null) + { + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Radars"); + } + else if (parts.Current.partPrefab.FindModuleImplementing() != null) + { + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Targeting"); + } + else if (parts.Current.partPrefab.FindModuleImplementing() != null + || parts.Current.partPrefab.FindModuleImplementing() != null) + { + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Control"); + } + else if (parts.Current.partPrefab.FindModuleImplementing() != null + || parts.Current.partPrefab.FindModuleImplementing() != null) + { + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Countermeasures"); + } + else + { + using (var resource = parts.Current.partPrefab.Resources.GetEnumerator()) + while (resource.MoveNext()) + // Very dumb check, but right now too lazy to implement a better one + if (resource.Current.resourceName.Contains("Ammo")) + parts.Current.partConfig.AddValue(AutoBDACategoryKey, "Ammo"); + } + } + } + } + + private void OnDestroy() + { + GameEvents.onGUIEditorToolbarReady.Remove(LoadBDArmoryCategory); + } + + public static string GetTexturePath(string category) + { + if (CategoryIcons.TryGetValue(category, out string value)) + return value; + return "BDArmory/Textures/icon"; + } + + private void LoadBDArmoryCategory() + { + StartCoroutine(BDArmoryCategory()); + } + + private IEnumerator BDArmoryCategory() + { + // Wait for filter extensions to do their thing + yield return null; + yield return null; + yield return null; + + // BDA Category + const string customCategoryName = "BDAParts"; + const string customDisplayCategoryName = "Armory"; + + FilterByFunctionCategory = PartCategorizer.Instance.filters.Find(f => f.button.categorydisplayName == "#autoLOC_453547"); + if (BDACategory != null && FilterByFunctionCategory.subcategories.Contains(BDACategory)) + { + yield break; + } + + Texture2D iconTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/icon", false); + RUI.Icons.Selectable.Icon icon = new RUI.Icons.Selectable.Icon("BDArmory", iconTex, iconTex, false); + + BDACategory = PartCategorizer.AddCustomSubcategoryFilter( + FilterByFunctionCategory, + customCategoryName, + customDisplayCategoryName, + icon, + part => PartInCurrentCategory(part) + ); + + BDACategory.button.btnToggleGeneric.onClick.AddListener(CategoryButtonClick); + } + + private void CategoryButtonClick(UnityEngine.EventSystems.PointerEventData pointerEventData, UIRadioButton.State state, UIRadioButton.CallType callType) + { + if (pointerEventData.button == UnityEngine.EventSystems.PointerEventData.InputButton.Right) + { + SettingsOpen = true; + SettingsWindow = new Rect(Input.mousePosition.x, Screen.height - Input.mousePosition.y, SettingsWidth, SettingsHeight); + pointerEventData.Use(); + } + } + + private void DrawSettingsWindow(int id) + { + GUI.Box(new Rect(0, 0, SettingsWidth, SettingsHeight), "BDA Category Settings"); + + if (BDArmorySettings.SHOW_CATEGORIES != (BDArmorySettings.SHOW_CATEGORIES = BDArmorySettings.SHOW_CATEGORIES = GUI.Toggle( + new Rect(SettingsMargin, SettingsLineHeight * 1.25f, SettingsWidth - (2 * SettingsMargin), SettingsLineHeight), + BDArmorySettings.SHOW_CATEGORIES, + "Subcategories" + ))) + { + PartCategorizer.Instance.editorPartList.Refresh(); + } + if (BDArmorySettings.AUTOCATEGORIZE_PARTS != (BDArmorySettings.AUTOCATEGORIZE_PARTS = BDArmorySettings.AUTOCATEGORIZE_PARTS = GUI.Toggle( + new Rect(SettingsMargin, SettingsLineHeight * 2.25f, SettingsWidth - (2 * SettingsMargin), SettingsLineHeight), + BDArmorySettings.AUTOCATEGORIZE_PARTS, + "Autocategorize parts" + ))) + { + PartCategorizer.Instance.editorPartList.Refresh(); + } + + BDGUIUtils.RepositionWindow(ref SettingsWindow); + BDGUIUtils.UseMouseEventInRect(SettingsWindow); + } + + private void CreateBDAPartBar() + { + // Check if we need the special categories + bool foundLegacy = false; + bool foundMisc = false; + List foundCategories = new List(); + using (var parts = PartLoader.LoadedPartsList.GetEnumerator()) + while (parts.MoveNext()) + { + if (parts.Current == null || !parts.Current.partPrefab || parts.Current.partConfig == null) + continue; + string cat = ""; + if (parts.Current.partConfig.TryGetValue(BDArmorySettings.AUTOCATEGORIZE_PARTS ? AutoBDACategoryKey : BDACategoryKey, ref cat)) + { + if (!Categories.Contains(cat)) + foundMisc = true; + else if (!foundCategories.Contains(cat)) + foundCategories.Add(cat); + } + // If part does not have a bdacategory but manufacturer is BDA. + else if (parts.Current.manufacturer == Misc.BDAEditorTools.Manufacturer) + foundLegacy = true; + } + Categories.RemoveAll(s => !foundCategories.Contains(s) && s != "All"); + if (foundMisc && !Categories.Contains("Misc")) + Categories.Add("Misc"); + if (foundLegacy && !Categories.Contains("Legacy")) + Categories.Add("Legacy"); + + // BDA part category bar + var BDAPartBarContainer = new GameObject(); + BDAPartBarContainer.name = "BDAPartBarContainer"; + BDAPartBar = BDAPartBarContainer.AddComponent(); + BDAPartBar.name = "BDAPartBar"; + BDAPartBarContainer.transform.SetParent(PartCategorizer.Instance.transform, false); + BDAPartBar.anchoredPosition = EditorPanels.Instance.partsEditorModes.panelTransform.anchoredPosition + new Vector2(-212, -126); + + // BDA part category bar background + // DOESN'T WORK, NOTHING WORKS. :( + + // BDA part category buttons + PartCategorizer.Category filterByFunctionCategory = PartCategorizer.Instance.filters.Find(f => f.button.categorydisplayName == "#autoLOC_453547"); + Vector3 button_offset = filterByFunctionCategory.subcategories[1].button.transform.position - filterByFunctionCategory.subcategories[0].button.transform.position; + using (var category = Categories.GetEnumerator()) + while (category.MoveNext()) + { + // Since I don't wanna deal with drawing pretty little buttons, we're making categories, + // stealing the buttons, and then removing the categories. + Texture2D iconTex = GameDatabase.Instance.GetTexture(GetTexturePath(category.Current), false); + RUI.Icons.Selectable.Icon icon = new RUI.Icons.Selectable.Icon("BDArmory", iconTex, iconTex, false); + string name = category.Current; + var categorizer_button = PartCategorizer.AddCustomSubcategoryFilter( + filterByFunctionCategory, + name, + name, + icon, + part => PartInCurrentCategory(part) + ); + var button = categorizer_button.button; + button.btnToggleGeneric.onClick.RemoveAllListeners(); + button.btnToggleGeneric.onFalse.RemoveAllListeners(); + button.btnToggleGeneric.onFalseBtn.RemoveAllListeners(); + button.btnToggleGeneric.onTrue.RemoveAllListeners(); + button.btnToggleGeneric.onTrueBtn.RemoveAllListeners(); + button.btnToggleGeneric.SetGroup(412440121); + button.transform.SetParent(BDAPartBar, false); + button.transform.position = new Vector3(BDACategory.button.transform.position.x + 34, 424, 750) + button_offset * SubcategoryButtons.Count; + categorizer_button.DeleteSubcategory(); + SubcategoryButtons.Add(button); + // Gotta use a saved value, because the enumerator changes the value during the run + button.btnToggleGeneric.onTrue.AddListener((x, y) => SetCategory(name)); + } + } + + private void SetCategory(string category) + { + CurrentCategory = category; + PartCategorizer.Instance.editorPartList.Refresh(); + } + + private bool PartInCurrentCategory(AvailablePart part) + { + switch (BDArmorySettings.SHOW_CATEGORIES ? CurrentCategory : "Legacy") + { + // A few special cases. + case "All": + return part.partConfig.HasValue(BDArmorySettings.AUTOCATEGORIZE_PARTS ? AutoBDACategoryKey : BDACategoryKey); + + case "Legacy": + return part.manufacturer == Misc.BDAEditorTools.Manufacturer; + + case "Misc": + { + string value = null; + return part.partConfig.TryGetValue(BDArmorySettings.AUTOCATEGORIZE_PARTS ? AutoBDACategoryKey : BDACategoryKey, ref value) + && (value == "Misc" || !Categories.Contains(value)); + } + default: + { + string value = null; + return part.partConfig.TryGetValue(BDArmorySettings.AUTOCATEGORIZE_PARTS ? AutoBDACategoryKey : BDACategoryKey, ref value) + && value == CurrentCategory; + } + } + } + + private void ExpandPartSelector(Vector3 offset) + { + if (BDAPartBar == null || !BDAPartBar.transform.IsChildOf(PartCategorizer.Instance.transform)) + CreateBDAPartBar(); + else + BDAPartBar.anchoredPosition += new Vector2(offset.x * 10, 0); + foreach (Transform child in EditorPanels.Instance.partsEditorModes.panelTransform.parent) + { + if (child.name == "PartCategorizer") + continue; + child.position += offset; + } + } + + void OnGUI() + { + if (!HighLogic.LoadedSceneIsEditor || BDACategory == null) + return; + + bool shouldOpen = BDArmorySettings.SHOW_CATEGORIES && FilterByFunctionCategory.button.activeButton.Value && BDACategory.button.activeButton.Value; + if (shouldOpen && !expanded) + { + ExpandPartSelector(offset); + expanded = true; + } + else if (!shouldOpen && expanded) + { + ExpandPartSelector(-offset); + expanded = false; + } + + if (SettingsOpen && Event.current.type == EventType.MouseDown + && !SettingsWindow.Contains(Event.current.mousePosition)) + { + SettingsOpen = false; + BDArmorySetup.SaveConfig(); + } + if (SettingsOpen) + { + SettingsWindow = GUI.Window(9476026, SettingsWindow, DrawSettingsWindow, "", BDArmorySetup.BDGuiSkin.window); + } + + if (EditorLogic.fetch != null) + { + if (SettingsOpen + && SettingsWindow.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)) + && !CameraMouseLook.GetMouseLook()) + { + EditorLogic.fetch.Lock(false, false, false, "BDA_CATEGORY_LOCK"); + } + else + { + EditorLogic.fetch.Unlock("BDA_CATEGORY_LOCK"); + } + } + } + } +} diff --git a/BDArmory/UI/BDAPersistantSettingsField.cs b/BDArmory/UI/BDAPersistantSettingsField.cs new file mode 100644 index 000000000..bed61535f --- /dev/null +++ b/BDArmory/UI/BDAPersistantSettingsField.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UniLinq; + +namespace BDArmory.UI +{ + [AttributeUsage(AttributeTargets.Field)] + public class BDAPersistantSettingsField : Attribute + { + public BDAPersistantSettingsField() + { + } + + public static void Save() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + + if (!fileNode.HasNode("BDASettings")) + { + fileNode.AddNode("BDASettings"); + } + + ConfigNode settings = fileNode.GetNode("BDASettings"); + IEnumerator field = typeof(BDArmorySettings).GetFields().AsEnumerable().GetEnumerator(); + while (field.MoveNext()) + { + if (field.Current == null) continue; + if (!field.Current.IsDefined(typeof(BDAPersistantSettingsField), false)) continue; + + settings.SetValue(field.Current.Name, field.Current.GetValue(null).ToString(), true); + } + field.Dispose(); + fileNode.Save(BDArmorySettings.settingsConfigURL); + } + + public static void Load() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + if (!fileNode.HasNode("BDASettings")) return; + + ConfigNode settings = fileNode.GetNode("BDASettings"); + + IEnumerator field = typeof(BDArmorySettings).GetFields().AsEnumerable().GetEnumerator(); + while (field.MoveNext()) + { + if (field.Current == null) continue; + if (!field.Current.IsDefined(typeof(BDAPersistantSettingsField), false)) continue; + + if (!settings.HasValue(field.Current.Name)) continue; + object parsedValue = BDArmorySettings.ParseValue(field.Current.FieldType, settings.GetValue(field.Current.Name)); + if (parsedValue != null) + { + field.Current.SetValue(null, parsedValue); + } + } + field.Dispose(); + } + } +} \ No newline at end of file diff --git a/BDArmory/UI/BDATargetManager.cs b/BDArmory/UI/BDATargetManager.cs new file mode 100644 index 000000000..d8260596c --- /dev/null +++ b/BDArmory/UI/BDATargetManager.cs @@ -0,0 +1,1005 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.CounterMeasure; +using BDArmory.Misc; +using BDArmory.Modules; +using BDArmory.Parts; +using BDArmory.Radar; +using BDArmory.Targeting; +using KSP.UI.Screens; +using UnityEngine; + +namespace BDArmory.UI +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class BDATargetManager : MonoBehaviour + { + private static Dictionary> TargetDatabase; + private static Dictionary> GPSTargets; + public static List ActiveLasers; + public static List FiredMissiles; + public static List LoadedBuildings; + public static List LoadedVessels; + public static BDATargetManager Instance; + + private StringBuilder debugString = new StringBuilder(); + private float updateTimer = 0; + + public static bool hasAddedButton; + + void Awake() + { + GameEvents.onGameStateLoad.Add(LoadGPSTargets); + GameEvents.onGameStateSave.Add(SaveGPSTargets); + LoadedBuildings = new List(); + DestructibleBuilding.OnLoaded.Add(AddBuilding); + LoadedVessels = new List(); + GameEvents.onVesselLoaded.Add(AddVessel); + GameEvents.onVesselGoOnRails.Add(RemoveVessel); + GameEvents.onVesselGoOffRails.Add(AddVessel); + GameEvents.onVesselCreate.Add(AddVessel); + GameEvents.onVesselDestroy.Add(CleanVesselList); + + Instance = this; + } + + void OnDestroy() + { + if (GameEvents.onGameStateLoad != null && GameEvents.onGameStateSave != null) + { + GameEvents.onGameStateLoad.Remove(LoadGPSTargets); + GameEvents.onGameStateSave.Remove(SaveGPSTargets); + } + + GPSTargets = new Dictionary>(); + + GameEvents.onVesselLoaded.Remove(AddVessel); + GameEvents.onVesselGoOnRails.Remove(RemoveVessel); + GameEvents.onVesselGoOffRails.Remove(AddVessel); + GameEvents.onVesselCreate.Remove(AddVessel); + GameEvents.onVesselDestroy.Remove(CleanVesselList); + } + + void Start() + { + //legacy targetDatabase + TargetDatabase = new Dictionary>(); + StartCoroutine(CleanDatabaseRoutine()); + + if (GPSTargets == null) + { + GPSTargets = new Dictionary>(); + } + + //Laser points + ActiveLasers = new List(); + + FiredMissiles = new List(); + + //AddToolbarButton(); + StartCoroutine(ToolbarButtonRoutine()); + } + + public static List GPSTargetList(BDTeam team) + { + if (team == null) + throw new ArgumentNullException("team"); + if (GPSTargets.TryGetValue(team, out List database)) + return database; + var newList = new List(); + GPSTargets.Add(team, newList); + return newList; + } + + void AddBuilding(DestructibleBuilding b) + { + if (!LoadedBuildings.Contains(b)) + { + LoadedBuildings.Add(b); + } + + LoadedBuildings.RemoveAll(x => x == null); + } + + void AddVessel(Vessel v) + { + if (!LoadedVessels.Contains(v)) + { + LoadedVessels.Add(v); + } + CleanVesselList(v); + } + + void RemoveVessel(Vessel v) + { + if (v != null) + { + LoadedVessels.Remove(v); + } + CleanVesselList(v); + } + + void CleanVesselList(Vessel v) + { + LoadedVessels.RemoveAll(ves => ves == null); + LoadedVessels.RemoveAll(ves => ves.loaded == false); + } + + void AddToolbarButton() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (!hasAddedButton) + { + Texture buttonTexture = GameDatabase.Instance.GetTexture(BDArmorySetup.textureDir + "icon", false); + ApplicationLauncher.Instance.AddModApplication(ShowToolbarGUI, HideToolbarGUI, Dummy, Dummy, Dummy, Dummy, ApplicationLauncher.AppScenes.FLIGHT, buttonTexture); + hasAddedButton = true; + } + } + } + + IEnumerator ToolbarButtonRoutine() + { + if (hasAddedButton) yield break; + if (!HighLogic.LoadedSceneIsFlight) yield break; + while (!ApplicationLauncher.Ready) + { + yield return null; + } + + AddToolbarButton(); + } + + public void ShowToolbarGUI() + { + BDArmorySetup.windowBDAToolBarEnabled = true; + } + + public void HideToolbarGUI() + { + BDArmorySetup.windowBDAToolBarEnabled = false; + } + + void Dummy() + { } + + void Update() + { + if (BDArmorySettings.DRAW_DEBUG_LABELS && FlightGlobals.ready) + { + updateTimer -= Time.fixedDeltaTime; + if (updateTimer < 0) + { + UpdateDebugLabels(); + updateTimer = 0.5f; //next update in half a sec only + } + } + } + + public static void RegisterLaserPoint(ModuleTargetingCamera cam) + { + if (ActiveLasers.Contains(cam)) + { + return; + } + else + { + ActiveLasers.Add(cam); + } + } + + ///// + ///// Gets the laser target painter with the least angle off boresight. Set the missileBase as the reference missilePosition. + ///// + ///// The laser target painter. + ///// Reference missilePosition. + ///// Max bore sight. + //public static ModuleTargetingCamera GetLaserTarget(MissileLauncher ml, bool parentOnly) + //{ + // return GetModuleTargeting(parentOnly, ml.transform.forward, ml.transform.position, ml.maxOffBoresight, ml.vessel, ml.SourceVessel); + // } + + // public static ModuleTargetingCamera GetLaserTarget(BDModularGuidance ml, bool parentOnly) + // { + // float maxOffBoresight = 45; + + // return GetModuleTargeting(parentOnly, ml.MissileReferenceTransform.forward, ml.MissileReferenceTransform.position, maxOffBoresight,ml.vessel,ml.SourceVessel); + // } + + /// + /// Gets the laser target painter with the least angle off boresight. Set the missileBase as the reference missilePosition. + /// + /// The laser target painter. + public static ModuleTargetingCamera GetLaserTarget(MissileBase ml, bool parentOnly) + { + return GetModuleTargeting(parentOnly, ml.GetForwardTransform(), ml.MissileReferenceTransform.position, ml.maxOffBoresight, ml.vessel, ml.SourceVessel); + } + + private static ModuleTargetingCamera GetModuleTargeting(bool parentOnly, Vector3 missilePosition, Vector3 position, float maxOffBoresight, Vessel vessel, Vessel sourceVessel) + { + ModuleTargetingCamera finalCam = null; + float smallestAngle = 360; + List.Enumerator cam = ActiveLasers.GetEnumerator(); + while (cam.MoveNext()) + { + if (cam.Current == null) continue; + if (parentOnly && !(cam.Current.vessel == vessel || cam.Current.vessel == sourceVessel)) continue; + if (!cam.Current.cameraEnabled || !cam.Current.groundStabilized || !cam.Current.surfaceDetected || + cam.Current.gimbalLimitReached) continue; + + float angle = Vector3.Angle(missilePosition, cam.Current.groundTargetPosition - position); + if (!(angle < maxOffBoresight) || !(angle < smallestAngle) || + !CanSeePosition(cam.Current.groundTargetPosition, vessel.transform.position, + (vessel.transform.position + missilePosition))) continue; + + smallestAngle = angle; + finalCam = cam.Current; + } + cam.Dispose(); + return finalCam; + } + + public static bool CanSeePosition(Vector3 groundTargetPosition, Vector3 vesselPosition, Vector3 missilePosition) + { + if ((groundTargetPosition - vesselPosition).sqrMagnitude < Mathf.Pow(20, 2)) + { + return false; + } + + float dist = BDArmorySettings.MAX_GUARD_VISUAL_RANGE; //replaced constant 10km with actual configured visual range + Ray ray = new Ray(missilePosition, groundTargetPosition - missilePosition); + ray.origin += 10 * ray.direction; + RaycastHit rayHit; + if (Physics.Raycast(ray, out rayHit, dist, 557057)) + { + if ((rayHit.point - groundTargetPosition).sqrMagnitude < 200) + { + return true; + } + else + { + return false; + } + } + + return true; + } + + /// + /// The the heat signature of a vessel (for Heat/IR targeting). + /// Returns the heat of the hottest part of the vessel + /// + /// Vessel + /// Heat signature value + public static float GetVesselHeatSignature(Vessel v) + { + float heatScore = 0f; + + List.Enumerator part = v.Parts.GetEnumerator(); + while (part.MoveNext()) + { + if (!part.Current) continue; + + float thisScore = (float)(part.Current.thermalInternalFluxPrevious + part.Current.skinTemperature); + heatScore = Mathf.Max(heatScore, thisScore); + } + + return heatScore; + } + + /// + /// Find a flare within acceptable thermal range that will "decoy" for the passed heatsignature + /// + public static TargetSignatureData GetFlareTarget(Ray ray, float scanRadius, float highpassThreshold, bool allAspect, float heatSignature) + { + TargetSignatureData flareTarget = TargetSignatureData.noTarget; + + List.Enumerator flare = BDArmorySetup.Flares.GetEnumerator(); + while (flare.MoveNext()) + { + if (!flare.Current) continue; + + float angle = Vector3.Angle(flare.Current.transform.position - ray.origin, ray.direction); + if (angle < scanRadius) + { + float score = flare.Current.thermal * Mathf.Clamp01(15 / angle); + + score *= Mathf.Pow(1400, 2) / Mathf.Clamp((flare.Current.transform.position - ray.origin).sqrMagnitude, 90000, 36000000); + score *= Mathf.Clamp(Vector3.Angle(flare.Current.transform.position - ray.origin, -VectorUtils.GetUpDirection(ray.origin)) / 90, 0.5f, 1.5f); + + // check acceptable range: + // flare cannot be too cool, but also not too bright + if ((score > heatSignature * 0.9) && (score < heatSignature * 1.15)) + { + flareTarget = new TargetSignatureData(flare.Current, score); + } + } + } + + return flareTarget; + } + + public static TargetSignatureData GetHeatTarget(Vessel sourceVessel, Vessel missileVessel, Ray ray, float scanRadius, float highpassThreshold, bool allAspect, MissileFire mf = null, bool favorGroundTargets = false) + { + float minMass = 0.05f; //otherwise the RAMs have trouble shooting down incoming missiles + TargetSignatureData finalData = TargetSignatureData.noTarget; + float finalScore = 0; + + foreach (Vessel vessel in LoadedVessels) + { + if (vessel == null) + { + continue; + } + if (!vessel || !vessel.loaded) + { + continue; + } + + if (vessel == sourceVessel || vessel == missileVessel) + { + continue; + } + + if (favorGroundTargets && !vessel.LandedOrSplashed) + { + // for AGM heat guidance + continue; + } + + TargetInfo tInfo = vessel.gameObject.GetComponent(); + + if (tInfo == null) + { + return finalData; + } + // If no weaponManager or no target or the target is not a missile with engines on..??? and the target weighs less than 50kg, abort. + if (mf == null || + !tInfo || + !(mf && tInfo.isMissile && (tInfo.MissileBaseModule.MissileState == MissileBase.MissileStates.Boost || tInfo.MissileBaseModule.MissileState == MissileBase.MissileStates.Cruise))) + { + if (vessel.GetTotalMass() < minMass) + { + continue; + } + } + + // Abort if target is friendly. + if (mf != null) + { + if (mf.Team.IsFriendly(tInfo.Team)) + { + continue; + } + } + float angle = Vector3.Angle(vessel.CoM - ray.origin, ray.direction); + if (angle < scanRadius) + { + if (RadarUtils.TerrainCheck(ray.origin, vessel.transform.position)) + continue; + + if (!allAspect) + { + if (!Misc.Misc.CheckSightLineExactDistance(ray.origin, vessel.CoM + vessel.Velocity(), Vector3.Distance(vessel.CoM, ray.origin), 5, 5)) + continue; + } + + float score = GetVesselHeatSignature(vessel) * Mathf.Clamp01(15 / angle); + score *= Mathf.Pow(1400, 2) / Mathf.Clamp((vessel.CoM - ray.origin).sqrMagnitude, 90000, 36000000); + + if (vessel.LandedOrSplashed && !favorGroundTargets) + { + score /= 4; + } + + score *= Mathf.Clamp(Vector3.Angle(vessel.transform.position - ray.origin, -VectorUtils.GetUpDirection(ray.origin)) / 90, 0.5f, 1.5f); + + if (score > finalScore) + { + finalScore = score; + finalData = new TargetSignatureData(vessel, score); + } + } + } + + // see if there are flares decoying us: + TargetSignatureData flareData = GetFlareTarget(ray, scanRadius, highpassThreshold, allAspect, finalScore); + + if (finalScore < highpassThreshold) + { + finalData = TargetSignatureData.noTarget; + } + + // return matching flare + if (!flareData.Equals(TargetSignatureData.noTarget)) + return flareData; + + //else return the target: + return finalData; + } + + void UpdateDebugLabels() + { + debugString.Length = 0; + + using (var team = TargetDatabase.GetEnumerator()) + while (team.MoveNext()) + { + debugString.Append($"Team {team.Current.Key} targets:"); + debugString.Append(Environment.NewLine); + foreach (TargetInfo targetInfo in team.Current.Value) + { + if (targetInfo) + { + if (!targetInfo.Vessel) + { + debugString.Append($"- A target with no vessel reference."); + debugString.Append(Environment.NewLine); + } + else + { + debugString.Append($"- {targetInfo.Vessel.vesselName} Engaged by {targetInfo.TotalEngaging()}"); + debugString.Append(Environment.NewLine); + } + } + else + { + debugString.Append($"- null target info."); + debugString.Append(Environment.NewLine); + } + } + } + + debugString.Append(Environment.NewLine); + debugString.Append($"Heat Signature: {GetVesselHeatSignature(FlightGlobals.ActiveVessel):#####}"); + debugString.Append(Environment.NewLine); + + debugString.Append($"Radar Signature: " + RadarUtils.GetVesselRadarSignature(FlightGlobals.ActiveVessel).radarModifiedSignature); + debugString.Append(Environment.NewLine); + + debugString.Append($"Chaff multiplier: " + RadarUtils.GetVesselChaffFactor(FlightGlobals.ActiveVessel)); + debugString.Append(Environment.NewLine); + + debugString.Append($"ECM Jammer Strength: " + FlightGlobals.ActiveVessel.gameObject.GetComponent()?.jammerStrength); + debugString.Append(Environment.NewLine); + + debugString.Append($"ECM Lockbreak Strength: " + FlightGlobals.ActiveVessel.gameObject.GetComponent()?.lockBreakStrength); + debugString.Append(Environment.NewLine); + } + + public void SaveGPSTargets(ConfigNode saveNode = null) + { + string saveTitle = HighLogic.CurrentGame.Title; + Debug.Log("[BDArmory]: Save title: " + saveTitle); + ConfigNode fileNode = ConfigNode.Load("GameData/BDArmory/gpsTargets.cfg"); + if (fileNode == null) + { + fileNode = new ConfigNode(); + fileNode.AddNode("BDARMORY"); + fileNode.Save("GameData/BDArmory/gpsTargets.cfg"); + } + + if (fileNode != null && fileNode.HasNode("BDARMORY")) + { + ConfigNode node = fileNode.GetNode("BDARMORY"); + + if (GPSTargets == null || !FlightGlobals.ready) + { + return; + } + + ConfigNode gpsNode = null; + if (node.HasNode("BDAGPSTargets")) + { + foreach (ConfigNode n in node.GetNodes("BDAGPSTargets")) + { + if (n.GetValue("SaveGame") == saveTitle) + { + gpsNode = n; + break; + } + } + + if (gpsNode == null) + { + gpsNode = node.AddNode("BDAGPSTargets"); + gpsNode.AddValue("SaveGame", saveTitle); + } + } + else + { + gpsNode = node.AddNode("BDAGPSTargets"); + gpsNode.AddValue("SaveGame", saveTitle); + } + + bool foundTargets = false; + using (var kvp = GPSTargets.GetEnumerator()) + while (kvp.MoveNext()) + if (kvp.Current.Value.Count > 0) + { + foundTargets = true; + break; + } + if (!foundTargets) + return; + + string targetString = GPSListToString(); + gpsNode.SetValue("Targets", targetString, true); + fileNode.Save("GameData/BDArmory/gpsTargets.cfg"); + Debug.Log("[BDArmory]: ==== Saved BDA GPS Targets ===="); + } + } + + void LoadGPSTargets(ConfigNode saveNode) + { + ConfigNode fileNode = ConfigNode.Load("GameData/BDArmory/gpsTargets.cfg"); + string saveTitle = HighLogic.CurrentGame.Title; + + if (fileNode != null && fileNode.HasNode("BDARMORY")) + { + ConfigNode node = fileNode.GetNode("BDARMORY"); + + foreach (ConfigNode gpsNode in node.GetNodes("BDAGPSTargets")) + { + if (gpsNode.HasValue("SaveGame") && gpsNode.GetValue("SaveGame") == saveTitle) + { + if (gpsNode.HasValue("Targets")) + { + string targetString = gpsNode.GetValue("Targets"); + if (targetString == string.Empty) + { + Debug.Log("[BDArmory]: ==== BDA GPS Target string was empty! ===="); + return; + } + StringToGPSList(targetString); + Debug.Log("[BDArmory]: ==== Loaded BDA GPS Targets ===="); + } + else + { + Debug.Log("[BDArmory]: ==== No BDA GPS Targets value found! ===="); + } + } + } + } + } + + // Because Unity's JsonConvert is a featureless pita. + [Serializable] + public class SerializableGPSData + { + public List Team = new List(); + public List Data = new List(); + + public SerializableGPSData(Dictionary> data) + { + using (var kvp = data.GetEnumerator()) + while (kvp.MoveNext()) + { + Team.Add(kvp.Current.Key.Name); + Data.Add(JsonUtility.ToJson(new SerializableGPSList(kvp.Current.Value))); + } + } + + public Dictionary> Load() + { + var value = new Dictionary>(); + for (int i = 0; i < Team.Count; ++i) + value.Add(BDTeam.Get(Team[i]), JsonUtility.FromJson(Data[i]).Load()); + return value; + } + } + + [Serializable] + public class SerializableGPSList + { + public List Data = new List(); + + public SerializableGPSList(List data) + { + using (var gps = data.GetEnumerator()) + while (gps.MoveNext()) + Data.Add(JsonUtility.ToJson(gps.Current)); + } + + public List Load() + { + var value = new List(); + using (var json = Data.GetEnumerator()) + while (json.MoveNext()) + value.Add(JsonUtility.FromJson(json.Current)); + return value; + } + } + + //format: very mangled json :( + private string GPSListToString() + { + return Misc.Misc.JsonCompat(JsonUtility.ToJson(new SerializableGPSData(GPSTargets))); + } + + private void StringToGPSList(string listString) + { + try + { + GPSTargets = JsonUtility.FromJson(Misc.Misc.JsonDecompat(listString)).Load(); + + Debug.Log("[BDArmory]: Loaded GPS Targets."); + } + catch { } + } + + IEnumerator CleanDatabaseRoutine() + { + while (enabled) + { + yield return new WaitForSeconds(5); + + using (var team = TargetDatabase.GetEnumerator()) + while (team.MoveNext()) + { + team.Current.Value.RemoveAll(target => target == null); + team.Current.Value.RemoveAll(target => target.Team == team.Current.Key); + team.Current.Value.RemoveAll(target => !target.isThreat); + } + } + } + + void RemoveTarget(TargetInfo target, BDTeam team) + { + TargetDatabase[team].Remove(target); + } + + public static void RemoveTarget(TargetInfo target) + { + using (var db = TargetDatabase.GetEnumerator()) + while (db.MoveNext()) + db.Current.Value.Remove(target); + } + + public static void ReportVessel(Vessel v, MissileFire reporter) + { + if (!v) return; + if (!reporter) return; + + TargetInfo info = v.gameObject.GetComponent(); + if (!info) + { + List.Enumerator mf = v.FindPartModulesImplementing().GetEnumerator(); + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + if (reporter.Team.IsEnemy(mf.Current.Team)) + { + info = v.gameObject.AddComponent(); + info.detectedTime[reporter.Team] = Time.time; + break; + } + } + mf.Dispose(); + + List.Enumerator ml = v.FindPartModulesImplementing().GetEnumerator(); + while (ml.MoveNext()) + { + if (ml.Current == null) continue; + if (ml.Current.HasFired) + { + if (reporter.Team.IsEnemy(ml.Current.Team)) + { + info = v.gameObject.AddComponent(); + info.detectedTime[reporter.Team] = Time.time; + break; + } + } + } + ml.Dispose(); + } + + // add target to database + if (info && reporter.Team.IsEnemy(info.Team)) + { + AddTarget(info, reporter.Team); + info.detectedTime[reporter.Team] = Time.time; + } + } + + public static void AddTarget(TargetInfo target, BDTeam reportingTeam) + { + if (target.Team == null) return; + if (!BDATargetManager.TargetList(reportingTeam).Contains(target)) + { + BDATargetManager.TargetList(reportingTeam).Add(target); + } + } + + public static List TargetList(BDTeam team) + { + if (TargetDatabase.TryGetValue(team, out List database)) + return database; + var newList = new List(); + TargetDatabase.Add(team, newList); + return newList; + } + + public static void ClearDatabase() + { + using (var teamDB = TargetDatabase.GetEnumerator()) + while (teamDB.MoveNext()) + { + using (var targetList = teamDB.Current.Value.GetEnumerator()) + while (targetList.MoveNext()) + targetList.Current.detectedTime.Clear(); + teamDB.Current.Value.Clear(); + } + } + + public static TargetInfo GetAirToAirTarget(MissileFire mf) + { + TargetInfo finalTarget = null; + + float finalTargetSuitability = 0; //this will determine how suitable the target is, based on where it is located relative to the targeting vessel and how far it is + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current.NumFriendliesEngaging(mf.Team) >= 2) continue; + if (target.Current && target.Current.Vessel && target.Current.isFlying && !target.Current.isMissile && target.Current.isThreat) + { + Vector3 targetRelPos = target.Current.Vessel.vesselTransform.position - mf.vessel.vesselTransform.position; + float targetSuitability = Vector3.Dot(targetRelPos.normalized, mf.vessel.ReferenceTransform.up); //prefer targets ahead to those behind + targetSuitability += 500 / (targetRelPos.magnitude + 100); + + if (finalTarget == null || (target.Current.NumFriendliesEngaging(mf.Team) < finalTarget.NumFriendliesEngaging(mf.Team)) || targetSuitability > finalTargetSuitability + finalTarget.NumFriendliesEngaging(mf.Team)) + { + finalTarget = target.Current; + finalTargetSuitability = targetSuitability; + } + } + } + + return finalTarget; + } + + //this will search for an AA target that is immediately in front of the AI during an extend when it would otherwise be helpless + public static TargetInfo GetAirToAirTargetAbortExtend(MissileFire mf, float maxDistance, float cosAngleCheck) + { + TargetInfo finalTarget = null; + + float finalTargetSuitability = 0; //this will determine how suitable the target is, based on where it is located relative to the targeting vessel and how far it is + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null || !target.Current.Vessel || target.Current.isLandedOrSurfaceSplashed || target.Current.isMissile || !target.Current.isThreat) continue; + Vector3 targetRelPos = target.Current.Vessel.vesselTransform.position - mf.vessel.vesselTransform.position; + + float distance, dot; + distance = targetRelPos.magnitude; + dot = Vector3.Dot(targetRelPos.normalized, mf.vessel.ReferenceTransform.up); + + if (distance > maxDistance || cosAngleCheck > dot) + continue; + + float targetSuitability = dot; //prefer targets ahead to those behind + targetSuitability += 500 / (distance + 100); //same suitability check as above + + if (finalTarget != null && !(targetSuitability > finalTargetSuitability)) continue; + //just pick the most suitable one + finalTarget = target.Current; + finalTargetSuitability = targetSuitability; + } + target.Dispose(); + return finalTarget; + } + + //returns the nearest friendly target + public static TargetInfo GetClosestFriendly(MissileFire mf) + { + TargetInfo finalTarget = null; + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null || !target.Current.Vessel || target.Current.weaponManager == mf) continue; + if (finalTarget == null || (target.Current.IsCloser(finalTarget, mf))) + { + finalTarget = target.Current; + } + } + target.Dispose(); + return finalTarget; + } + + //returns the target that owns this weapon manager + public static TargetInfo GetTargetFromWeaponManager(MissileFire mf) + { + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current.Vessel && target.Current.weaponManager == mf) + { + return target.Current; + } + } + target.Dispose(); + return null; + } + + public static TargetInfo GetClosestTarget(MissileFire mf) + { + TargetInfo finalTarget = null; + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current && target.Current.Vessel && mf.CanSeeTarget(target.Current) && !target.Current.isMissile) + { + if (finalTarget == null || (target.Current.IsCloser(finalTarget, mf))) + { + finalTarget = target.Current; + } + } + } + target.Dispose(); + return finalTarget; + } + + public static List GetAllTargetsExcluding(List excluding, MissileFire mf) + { + List finalTargets = new List(); + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current && target.Current.Vessel && mf.CanSeeTarget(target.Current) && !excluding.Contains(target.Current)) + { + finalTargets.Add(target.Current); + } + } + target.Dispose(); + return finalTargets; + } + + public static TargetInfo GetLeastEngagedTarget(MissileFire mf) + { + TargetInfo finalTarget = null; + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current && target.Current.Vessel && mf.CanSeeTarget(target.Current) && !target.Current.isMissile && target.Current.isThreat) + { + if (finalTarget == null || target.Current.NumFriendliesEngaging(mf.Team) < finalTarget.NumFriendliesEngaging(mf.Team)) + { + finalTarget = target.Current; + } + } + } + target.Dispose(); + return finalTarget; + } + + public static TargetInfo GetMissileTarget(MissileFire mf, bool targetingMeOnly = false) + { + TargetInfo finalTarget = null; + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current && target.Current.Vessel && target.Current.isMissile && target.Current.isThreat && mf.CanSeeTarget(target.Current)) + { + if (target.Current.MissileBaseModule) + { + if (targetingMeOnly) + { + if (Vector3.SqrMagnitude(target.Current.MissileBaseModule.TargetPosition - mf.vessel.CoM) > 60 * 60) + { + continue; + } + } + } + else + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + Debug.LogWarning("checking target missile - doesn't have missile module"); + } + + if (((finalTarget == null && target.Current.NumFriendliesEngaging(mf.Team) < 2) || (finalTarget != null && target.Current.NumFriendliesEngaging(mf.Team) < finalTarget.NumFriendliesEngaging(mf.Team)))) + { + finalTarget = target.Current; + } + } + } + target.Dispose(); + return finalTarget; + } + + public static TargetInfo GetUnengagedMissileTarget(MissileFire mf) + { + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current && target.Current.Vessel && mf.CanSeeTarget(target.Current) && target.Current.isMissile && target.Current.isThreat) + { + if (target.Current.NumFriendliesEngaging(mf.Team) == 0) + { + return target.Current; + } + } + } + target.Dispose(); + return null; + } + + public static TargetInfo GetClosestMissileTarget(MissileFire mf) + { + TargetInfo finalTarget = null; + + List.Enumerator target = TargetList(mf.Team).GetEnumerator(); + while (target.MoveNext()) + { + if (target.Current == null) continue; + if (target.Current && target.Current.Vessel && mf.CanSeeTarget(target.Current) && target.Current.isMissile) + { + bool isHostile = false; + if (target.Current.isThreat) + { + isHostile = true; + } + + if (isHostile && (finalTarget == null || target.Current.IsCloser(finalTarget, mf))) + { + finalTarget = target.Current; + } + } + } + target.Dispose(); + return finalTarget; + } + + //checks to see if a friendly is too close to the gun trajectory to fire them + public static bool CheckSafeToFireGuns(MissileFire weaponManager, Vector3 aimDirection, float safeDistance, float cosUnsafeAngle) + { + if (weaponManager == null) return false; + if (weaponManager.vessel == null) return false; + + using (var friendlyTarget = FlightGlobals.Vessels.GetEnumerator()) + while (friendlyTarget.MoveNext()) + { + if (friendlyTarget.Current == null || friendlyTarget.Current == weaponManager.vessel) + continue; + var wms = friendlyTarget.Current.FindPartModuleImplementing(); + if (wms != null && wms.Team != weaponManager.Team) + continue; + Vector3 targetDistance = friendlyTarget.Current.CoM - weaponManager.vessel.CoM; + float friendlyPosDot = Vector3.Dot(targetDistance, aimDirection); + if (friendlyPosDot <= 0) + continue; + float friendlyDistance = targetDistance.magnitude; + float friendlyPosDotNorm = friendlyPosDot / friendlyDistance; //scale down the dot to be a 0-1 so we can check it againts cosUnsafeAngle + + if (friendlyDistance < safeDistance && cosUnsafeAngle < friendlyPosDotNorm) //if it's too close and it's within the Unsafe Angle, don't fire + return false; + } + return true; + } + + void OnGUI() + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + GUI.Label(new Rect(600, 100, 600, 600), debugString.ToString()); + } + } + } +} diff --git a/BDArmory/UI/BDAWindowSettingsField.cs b/BDArmory/UI/BDAWindowSettingsField.cs new file mode 100644 index 000000000..1c45074d2 --- /dev/null +++ b/BDArmory/UI/BDAWindowSettingsField.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using BDArmory.Core; +using UniLinq; + +namespace BDArmory.UI +{ + [AttributeUsage(AttributeTargets.Field)] + public class BDAWindowSettingsField : Attribute + { + public BDAWindowSettingsField() + { + } + + public static void Save() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + + if (!fileNode.HasNode("BDAWindows")) + { + fileNode.AddNode("BDAWindows"); + } + + ConfigNode settings = fileNode.GetNode("BDAWindows"); + + IEnumerator field = typeof(BDArmorySetup).GetFields().AsEnumerable().GetEnumerator(); + while (field.MoveNext()) + { + if (field.Current == null) continue; + if (!field.Current.IsDefined(typeof(BDAWindowSettingsField), false)) continue; + + settings.SetValue(field.Current.Name, field.Current.GetValue(null).ToString(), true); + } + field.Dispose(); + fileNode.Save(BDArmorySettings.settingsConfigURL); + } + + public static void Load() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + if (!fileNode.HasNode("BDAWindows")) return; + + ConfigNode settings = fileNode.GetNode("BDAWindows"); + + IEnumerator field = typeof(BDArmorySetup).GetFields().AsEnumerable().GetEnumerator(); + while (field.MoveNext()) + { + if (field.Current == null) continue; + if (!field.Current.IsDefined(typeof(BDAWindowSettingsField), false)) continue; + if (!settings.HasValue(field.Current.Name)) continue; + + object parsedValue = BDAPersistantSettingsField.ParseValue(field.Current.FieldType, settings.GetValue(field.Current.Name)); + if (parsedValue != null) + { + field.Current.SetValue(null, parsedValue); + } + } + field.Dispose(); + } + } +} diff --git a/BDArmory/UI/BDArmorySetup.cs b/BDArmory/UI/BDArmorySetup.cs new file mode 100644 index 000000000..09689ddf9 --- /dev/null +++ b/BDArmory/UI/BDArmorySetup.cs @@ -0,0 +1,1736 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using BDArmory.Bullets; +using BDArmory.Control; +using BDArmory.Core; +using BDArmory.Core.Extension; +using BDArmory.CounterMeasure; +using BDArmory.Misc; +using BDArmory.Modules; +using BDArmory.Parts; +using BDArmory.Radar; +using UnityEngine; +using KSP.Localization; + +namespace BDArmory.UI +{ + [KSPAddon(KSPAddon.Startup.EveryScene, false)] + public class BDArmorySetup : MonoBehaviour + { + public static bool SMART_GUARDS = true; + public static bool showTargets = true; + + //=======Window position settings Git Issue #13 + [BDAWindowSettingsField] public static Rect WindowRectToolbar; + [BDAWindowSettingsField] public static Rect WindowRectGps; + [BDAWindowSettingsField] public static Rect WindowRectSettings; + [BDAWindowSettingsField] public static Rect WindowRectRadar; + [BDAWindowSettingsField] public static Rect WindowRectRwr; + [BDAWindowSettingsField] public static Rect WindowRectVesselSwitcher; + [BDAWindowSettingsField] public static Rect WindowRectWingCommander = new Rect(45, 75, 240, 800); + [BDAWindowSettingsField] public static Rect WindowRectTargetingCam; + + //reflection field lists + FieldInfo[] iFs; + + FieldInfo[] inputFields + { + get + { + if (iFs == null) + { + iFs = typeof(BDInputSettingsFields).GetFields(); + } + return iFs; + } + } + + //dependency checks + bool ModuleManagerLoaded = false; + bool PhysicsRangeExtenderLoaded = false; + + //EVENTS + public delegate void VolumeChange(); + + public static event VolumeChange OnVolumeChange; + + public delegate void SavedSettings(); + + public static event SavedSettings OnSavedSettings; + + public delegate void PeaceEnabled(); + + public static event PeaceEnabled OnPeaceEnabled; + + //particle optimization + public static int numberOfParticleEmitters = 0; + public static BDArmorySetup Instance; + public static bool GAME_UI_ENABLED = true; + public string Version { get; private set; } = "Unknown"; + + //settings gui + public static bool windowSettingsEnabled; + public string fireKeyGui; + + //editor alignment + public static bool showWeaponAlignment; + + // Gui Skin + public static GUISkin BDGuiSkin = HighLogic.Skin; + + //toolbar gui + public static bool hasAddedButton = false; + public static bool windowBDAToolBarEnabled; + float toolWindowWidth = 300; + float toolWindowHeight = 100; + bool showWeaponList; + bool showGuardMenu; + bool showModules; + int numberOfModules; + bool showWindowGPS; + + //gps window + public bool showingWindowGPS + { + get { return showWindowGPS; } + } + + bool maySavethisInstance = false; + float gpsEntryCount; + float gpsEntryHeight = 24; + float gpsBorder = 5; + bool editingGPSName; + int editingGPSNameIndex; + bool hasEnteredGPSName; + string newGPSName = String.Empty; + + public MissileFire ActiveWeaponManager; + public bool missileWarning; + public float missileWarningTime = 0; + + //load range stuff + VesselRanges combatVesselRanges = new VesselRanges(); + float physRangeTimer; + + public static List Flares = new List(); + + //gui styles + GUIStyle centerLabel; + GUIStyle centerLabelRed; + GUIStyle centerLabelOrange; + GUIStyle centerLabelBlue; + GUIStyle leftLabel; + GUIStyle leftLabelRed; + GUIStyle rightLabelRed; + GUIStyle leftLabelGray; + GUIStyle rippleSliderStyle; + GUIStyle rippleThumbStyle; + GUIStyle kspTitleLabel; + GUIStyle middleLeftLabel; + GUIStyle middleLeftLabelOrange; + GUIStyle targetModeStyle; + GUIStyle targetModeStyleSelected; + GUIStyle waterMarkStyle; + GUIStyle redErrorStyle; + GUIStyle redErrorShadowStyle; + + public SortedList Teams = new SortedList + { + { "Neutral", new BDTeam("Neutral", neutral: true) } + }; + + //competition mode + float competitionDist = 8000; + string compDistGui = "8000"; + + #region Textures + + public static string textureDir = "BDArmory/Textures/"; + + bool drawCursor; + Texture2D cursorTexture = GameDatabase.Instance.GetTexture(textureDir + "aimer", false); + + private Texture2D dti; + + public Texture2D directionTriangleIcon + { + get { return dti ? dti : dti = GameDatabase.Instance.GetTexture(textureDir + "directionIcon", false); } + } + + private Texture2D cgs; + + public Texture2D crossedGreenSquare + { + get { return cgs ? cgs : cgs = GameDatabase.Instance.GetTexture(textureDir + "crossedGreenSquare", false); } + } + + private Texture2D dlgs; + + public Texture2D dottedLargeGreenCircle + { + get + { + return dlgs + ? dlgs + : dlgs = GameDatabase.Instance.GetTexture(textureDir + "dottedLargeGreenCircle", false); + } + } + + private Texture2D ogs; + + public Texture2D openGreenSquare + { + get { return ogs ? ogs : ogs = GameDatabase.Instance.GetTexture(textureDir + "openGreenSquare", false); } + } + + private Texture2D gdott; + + public Texture2D greenDotTexture + { + get { return gdott ? gdott : gdott = GameDatabase.Instance.GetTexture(textureDir + "greenDot", false); } + } + + private Texture2D gdt; + + public Texture2D greenDiamondTexture + { + get { return gdt ? gdt : gdt = GameDatabase.Instance.GetTexture(textureDir + "greenDiamond", false); } + } + + private Texture2D lgct; + + public Texture2D largeGreenCircleTexture + { + get { return lgct ? lgct : lgct = GameDatabase.Instance.GetTexture(textureDir + "greenCircle3", false); } + } + + private Texture2D gct; + + public Texture2D greenCircleTexture + { + get { return gct ? gct : gct = GameDatabase.Instance.GetTexture(textureDir + "greenCircle2", false); } + } + + private Texture2D gpct; + + public Texture2D greenPointCircleTexture + { + get + { + if (gpct == null) + { + gpct = GameDatabase.Instance.GetTexture(textureDir + "greenPointCircle", false); + } + return gpct; + } + } + + private Texture2D gspct; + + public Texture2D greenSpikedPointCircleTexture + { + get + { + return gspct ? gspct : gspct = GameDatabase.Instance.GetTexture(textureDir + "greenSpikedCircle", false); + } + } + + private Texture2D wSqr; + + public Texture2D whiteSquareTexture + { + get { return wSqr ? wSqr : wSqr = GameDatabase.Instance.GetTexture(textureDir + "whiteSquare", false); } + } + + private Texture2D oWSqr; + + public Texture2D openWhiteSquareTexture + { + get + { + return oWSqr ? oWSqr : oWSqr = GameDatabase.Instance.GetTexture(textureDir + "openWhiteSquare", false); + ; + } + } + + private Texture2D tDir; + + public Texture2D targetDirectionTexture + { + get + { + return tDir + ? tDir + : tDir = GameDatabase.Instance.GetTexture(textureDir + "targetDirectionIndicator", false); + } + } + + private Texture2D hInd; + + public Texture2D horizonIndicatorTexture + { + get + { + return hInd ? hInd : hInd = GameDatabase.Instance.GetTexture(textureDir + "horizonIndicator", false); + } + } + + private Texture2D si; + + public Texture2D settingsIconTexture + { + get { return si ? si : si = GameDatabase.Instance.GetTexture(textureDir + "settingsIcon", false); } + } + + #endregion Textures + + public static bool GameIsPaused + { + get { return PauseMenu.isOpen || Time.timeScale == 0; } + } + + void Start() + { + Instance = this; + + //wmgr toolbar + if (HighLogic.LoadedSceneIsFlight) + maySavethisInstance = true; //otherwise later we should NOT save the current window positions! + + // Create settings file if not present. + if (ConfigNode.Load(BDArmorySettings.settingsConfigURL) == null) + { + var node = new ConfigNode(); + node.AddNode("BDASettings"); + node.Save(BDArmorySettings.settingsConfigURL); + } + + // window position settings + WindowRectToolbar = new Rect(Screen.width - toolWindowWidth - 40, 150, toolWindowWidth, toolWindowHeight); + // Default, if not in file. + WindowRectGps = new Rect(0, 0, WindowRectToolbar.width - 10, 0); + SetupSettingsSize(); + BDAWindowSettingsField.Load(); + CheckIfWindowsSettingsAreWithinScreen(); + + WindowRectGps.width = WindowRectToolbar.width - 10; + + //settings + LoadConfig(); + + physRangeTimer = Time.time; + GAME_UI_ENABLED = true; + fireKeyGui = BDInputSettingsFields.WEAP_FIRE_KEY.inputString; + + //setup gui styles + centerLabel = new GUIStyle(); + centerLabel.alignment = TextAnchor.UpperCenter; + centerLabel.normal.textColor = Color.white; + + centerLabelRed = new GUIStyle(); + centerLabelRed.alignment = TextAnchor.UpperCenter; + centerLabelRed.normal.textColor = Color.red; + + centerLabelOrange = new GUIStyle(); + centerLabelOrange.alignment = TextAnchor.UpperCenter; + centerLabelOrange.normal.textColor = XKCDColors.BloodOrange; + + centerLabelBlue = new GUIStyle(); + centerLabelBlue.alignment = TextAnchor.UpperCenter; + centerLabelBlue.normal.textColor = XKCDColors.AquaBlue; + + leftLabel = new GUIStyle(); + leftLabel.alignment = TextAnchor.UpperLeft; + leftLabel.normal.textColor = Color.white; + + middleLeftLabel = new GUIStyle(leftLabel); + middleLeftLabel.alignment = TextAnchor.MiddleLeft; + + middleLeftLabelOrange = new GUIStyle(middleLeftLabel); + middleLeftLabelOrange.normal.textColor = XKCDColors.BloodOrange; + + targetModeStyle = new GUIStyle(); + targetModeStyle.alignment = TextAnchor.MiddleRight; + targetModeStyle.fontSize = 9; + targetModeStyle.normal.textColor = Color.white; + + targetModeStyleSelected = new GUIStyle(targetModeStyle); + targetModeStyleSelected.normal.textColor = XKCDColors.BloodOrange; + + waterMarkStyle = new GUIStyle(middleLeftLabel); + waterMarkStyle.normal.textColor = XKCDColors.LightBlueGrey; + + leftLabelRed = new GUIStyle(); + leftLabelRed.alignment = TextAnchor.UpperLeft; + leftLabelRed.normal.textColor = Color.red; + + rightLabelRed = new GUIStyle(); + rightLabelRed.alignment = TextAnchor.UpperRight; + rightLabelRed.normal.textColor = Color.red; + + leftLabelGray = new GUIStyle(); + leftLabelGray.alignment = TextAnchor.UpperLeft; + leftLabelGray.normal.textColor = Color.gray; + + rippleSliderStyle = new GUIStyle(BDGuiSkin.horizontalSlider); + rippleThumbStyle = new GUIStyle(BDGuiSkin.horizontalSliderThumb); + rippleSliderStyle.fixedHeight = rippleThumbStyle.fixedHeight = 0; + + kspTitleLabel = new GUIStyle(); + kspTitleLabel.normal.textColor = BDGuiSkin.window.normal.textColor; + kspTitleLabel.font = BDGuiSkin.window.font; + kspTitleLabel.fontSize = BDGuiSkin.window.fontSize; + kspTitleLabel.fontStyle = BDGuiSkin.window.fontStyle; + kspTitleLabel.alignment = TextAnchor.UpperCenter; + + redErrorStyle = new GUIStyle(BDGuiSkin.label); + redErrorStyle.normal.textColor = Color.red; + redErrorStyle.fontStyle = FontStyle.Bold; + redErrorStyle.fontSize = 22; + redErrorStyle.alignment = TextAnchor.UpperCenter; + + redErrorShadowStyle = new GUIStyle(redErrorStyle); + redErrorShadowStyle.normal.textColor = new Color(0, 0, 0, 0.75f); + // + + using (var a = AppDomain.CurrentDomain.GetAssemblies().ToList().GetEnumerator()) + while (a.MoveNext()) + { + string name = a.Current.FullName.Split(new char[1] { ',' })[0]; + switch (name) + { + case "ModuleManager": + ModuleManagerLoaded = true; + break; + + case "PhysicsRangeExtender": + PhysicsRangeExtenderLoaded = true; + break; + + case "BDArmory": + Version = a.Current.GetName().Version.ToString(); + break; + } + } + + if (HighLogic.LoadedSceneIsFlight) + { + SaveVolumeSettings(); + + GameEvents.onHideUI.Add(HideGameUI); + GameEvents.onShowUI.Add(ShowGameUI); + GameEvents.onVesselGoOffRails.Add(OnVesselGoOffRails); + GameEvents.OnGameSettingsApplied.Add(SaveVolumeSettings); + + GameEvents.onVesselChange.Add(VesselChange); + } + + BulletInfo.Load(); + } + + private void CheckIfWindowsSettingsAreWithinScreen() + { + BDGUIUtils.RepositionWindow(ref WindowRectToolbar); + BDGUIUtils.RepositionWindow(ref WindowRectSettings); + BDGUIUtils.RepositionWindow(ref WindowRectRwr); + BDGUIUtils.RepositionWindow(ref WindowRectVesselSwitcher); + BDGUIUtils.RepositionWindow(ref WindowRectWingCommander); + BDGUIUtils.RepositionWindow(ref WindowRectTargetingCam); + } + + void Update() + { + if (HighLogic.LoadedSceneIsFlight) + { + if (missileWarning && Time.time - missileWarningTime > 1.5f) + { + missileWarning = false; + } + + if (Input.GetKeyDown(KeyCode.KeypadMultiply)) + { + windowBDAToolBarEnabled = !windowBDAToolBarEnabled; + } + } + else if (HighLogic.LoadedSceneIsEditor) + { + if (Input.GetKeyDown(KeyCode.F2)) + { + showWeaponAlignment = !showWeaponAlignment; + } + } + + if (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) + { + if (Input.GetKeyDown(KeyCode.B)) + { + ToggleWindowSettings(); + } + } + } + + void ToggleWindowSettings() + { + if (HighLogic.LoadedScene == GameScenes.LOADING || HighLogic.LoadedScene == GameScenes.LOADINGBUFFER) + { + return; + } + + windowSettingsEnabled = !windowSettingsEnabled; + if (windowSettingsEnabled) + { + LoadConfig(); + } + else + { + SaveConfig(); + } + } + + void LateUpdate() + { + if (HighLogic.LoadedSceneIsFlight) + { + //UpdateCursorState(); + } + } + + public void UpdateCursorState() + { + if (ActiveWeaponManager == null) + { + drawCursor = false; + //Screen.showCursor = true; + Cursor.visible = true; + return; + } + + if (!GAME_UI_ENABLED || CameraMouseLook.MouseLocked) + { + drawCursor = false; + Cursor.visible = false; + return; + } + + drawCursor = false; + if (!MapView.MapIsEnabled && !Misc.Misc.CheckMouseIsOnGui() && !PauseMenu.isOpen) + { + if (ActiveWeaponManager.selectedWeapon != null && ActiveWeaponManager.weaponIndex > 0 && + !ActiveWeaponManager.guardMode) + { + if (ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || + ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser) + { + ModuleWeapon mw = + ActiveWeaponManager.selectedWeapon.GetPart().FindModuleImplementing(); + if (mw.weaponState == ModuleWeapon.WeaponStates.Enabled && mw.maxPitch > 1 && !mw.slaved && + !mw.aiControlled) + { + //Screen.showCursor = false; + Cursor.visible = false; + drawCursor = true; + return; + } + } + else if (ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) + { + RocketLauncher rl = + ActiveWeaponManager.selectedWeapon.GetPart().FindModuleImplementing(); + if (rl.readyToFire && rl.turret) + { + //Screen.showCursor = false; + Cursor.visible = false; + drawCursor = true; + return; + } + } + } + } + + //Screen.showCursor = true; + Cursor.visible = true; + } + + void VesselChange(Vessel v) + { + if (v.isActiveVessel) + { + GetWeaponManager(); + Instance.UpdateCursorState(); + } + } + + void GetWeaponManager() + { + using (List.Enumerator mf = FlightGlobals.ActiveVessel.FindPartModulesImplementing().GetEnumerator()) + while (mf.MoveNext()) + { + if (mf.Current == null) continue; + ActiveWeaponManager = mf.Current; + return; + } + ActiveWeaponManager = null; + return; + } + + public static void LoadConfig() + { + try + { + Debug.Log("[BDArmory]=== Loading settings.cfg ==="); + + BDAPersistantSettingsField.Load(); + BDInputSettingsFields.LoadSettings(); + } + catch (NullReferenceException) + { + Debug.Log("[BDArmory]=== Failed to load settings config ==="); + } + } + + public static void SaveConfig() + { + try + { + Debug.Log("[BDArmory] == Saving settings.cfg == "); + + BDAPersistantSettingsField.Save(); + + BDInputSettingsFields.SaveSettings(); + + if (OnSavedSettings != null) + { + OnSavedSettings(); + } + } + catch (NullReferenceException) + { + Debug.Log("[BDArmory]: === Failed to save settings.cfg ===="); + } + } + + #region GUI + + void OnGUI() + { + if (!GAME_UI_ENABLED) return; + if (windowSettingsEnabled) + { + WindowRectSettings = GUI.Window(129419, WindowRectSettings, WindowSettings, GUIContent.none); + } + + if (drawCursor) + { + //mouse cursor + int origDepth = GUI.depth; + GUI.depth = -100; + float cursorSize = 40; + Vector3 cursorPos = Input.mousePosition; + Rect cursorRect = new Rect(cursorPos.x - (cursorSize / 2), Screen.height - cursorPos.y - (cursorSize / 2), cursorSize, cursorSize); + GUI.DrawTexture(cursorRect, cursorTexture); + GUI.depth = origDepth; + } + + if (!windowBDAToolBarEnabled || !HighLogic.LoadedSceneIsFlight) return; + WindowRectToolbar = GUI.Window(321, WindowRectToolbar, WindowBDAToolbar, Localizer.Format("#LOC_BDArmory_WMWindow_title"), BDGuiSkin.window);//"BDA Weapon Manager" + BDGUIUtils.UseMouseEventInRect(WindowRectToolbar); + if (showWindowGPS && ActiveWeaponManager) + { + //gpsWindowRect = GUI.Window(424333, gpsWindowRect, GPSWindow, "", GUI.skin.box); + BDGUIUtils.UseMouseEventInRect(WindowRectGps); + List.Enumerator coord = + BDATargetManager.GPSTargetList(ActiveWeaponManager.Team).GetEnumerator(); + while (coord.MoveNext()) + { + BDGUIUtils.DrawTextureOnWorldPos(coord.Current.worldPos, Instance.greenDotTexture, new Vector2(8, 8), 0); + } + coord.Dispose(); + } + + // big error messages for missing dependencies + if (ModuleManagerLoaded && PhysicsRangeExtenderLoaded) return; + string message = (ModuleManagerLoaded ? "Physics Range Extender" : "Module Manager") + + " is missing. BDA will not work properly."; + GUI.Label(new Rect(0 + 2, Screen.height / 6 + 2, Screen.width, 100), + message, redErrorShadowStyle); + GUI.Label(new Rect(0, Screen.height / 6, Screen.width, 100), + message, redErrorStyle); + } + + public bool hasVS = false; + public bool showVSGUI; + + float rippleHeight; + float weaponsHeight; + float guardHeight; + float modulesHeight; + float gpsHeight; + bool toolMinimized; + + void WindowBDAToolbar(int windowID) + { + GUI.DragWindow(new Rect(30, 0, toolWindowWidth - 90, 30)); + + float line = 0; + float leftIndent = 10; + float contentWidth = (toolWindowWidth) - (2 * leftIndent); + float contentTop = 10; + float entryHeight = 20; + + line += 1.25f; + line += 0.25f; + + // Version. + GUI.Label(new Rect(toolWindowWidth - 30 - 28 - 70, 23, 70, 10), Version, waterMarkStyle); + + //SETTINGS BUTTON + if (!BDKeyBinder.current && + GUI.Button(new Rect(toolWindowWidth - 30, 4, 26, 26), settingsIconTexture, BDGuiSkin.button)) + { + ToggleWindowSettings(); + } + + //vesselswitcher button + if (hasVS) + { + GUIStyle vsStyle = showVSGUI ? BDGuiSkin.box : BDGuiSkin.button; + if (GUI.Button(new Rect(toolWindowWidth - 30 - 28, 4, 26, 26), "VS", vsStyle)) + { + showVSGUI = !showVSGUI; + } + } + + if (ActiveWeaponManager != null) + { + //MINIMIZE BUTTON + toolMinimized = GUI.Toggle(new Rect(4, 4, 26, 26), toolMinimized, "_", + toolMinimized ? BDGuiSkin.box : BDGuiSkin.button); + + GUIStyle armedLabelStyle; + Rect armedRect = new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 2, entryHeight); + if (ActiveWeaponManager.guardMode) + { + if (GUI.Button(armedRect, "- " + Localizer.Format("#LOC_BDArmory_WMWindow_GuardModebtn") + " -", BDGuiSkin.box))//Guard Mode + { + showGuardMenu = true; + } + } + else + { + string armedText = Localizer.Format("#LOC_BDArmory_WMWindow_ArmedText");//"Trigger is " + if (ActiveWeaponManager.isArmed) + { + armedText += Localizer.Format("#LOC_BDArmory_WMWindow_ArmedText_ARMED");//"ARMED." + armedLabelStyle = BDGuiSkin.box; + } + else + { + armedText += Localizer.Format("#LOC_BDArmory_WMWindow_ArmedText_DisArmed");//"disarmed." + armedLabelStyle = BDGuiSkin.button; + } + if (GUI.Button(armedRect, armedText, armedLabelStyle)) + { + ActiveWeaponManager.ToggleArm(); + } + } + + GUIStyle teamButtonStyle = BDGuiSkin.box; + string teamText = $"{Localizer.Format("#LOC_BDArmory_WMWindow_TeamText")}: {ActiveWeaponManager.Team.Name}";//Team + + if ( + GUI.Button( + new Rect(leftIndent + (contentWidth / 2), contentTop + (line * entryHeight), contentWidth / 2, + entryHeight), teamText, teamButtonStyle)) + { + if (Event.current.button == 1) + { + BDTeamSelector.Instance.Open(ActiveWeaponManager, new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)); + } + else + { + ActiveWeaponManager.NextTeam(); + } + } + line++; + line += 0.25f; + string weaponName = ActiveWeaponManager.selectedWeaponString; + // = ActiveWeaponManager.selectedWeapon == null ? "None" : ActiveWeaponManager.selectedWeapon.GetShortName(); + string selectionText = Localizer.Format("#LOC_BDArmory_WMWindow_selectionText", weaponName);//Weapon: <<1>> + GUI.Label(new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth, entryHeight * 1.25f), selectionText, BDGuiSkin.box); + line += 1.25f; + line += 0.1f; + //if weapon can ripple, show option and slider. + if (ActiveWeaponManager.hasLoadedRippleData && ActiveWeaponManager.canRipple) + { + if (ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) + { + string rippleText = ActiveWeaponManager.rippleFire + ? Localizer.Format("#LOC_BDArmory_WMWindow_rippleText1", ActiveWeaponManager.gunRippleRpm.ToString("0"))//"Barrage: " + + " RPM" + : Localizer.Format("#LOC_BDArmory_WMWindow_rippleText2");//"Salvo" + GUIStyle rippleStyle = ActiveWeaponManager.rippleFire + ? BDGuiSkin.box + : BDGuiSkin.button; + if ( + GUI.Button( + new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 2, entryHeight * 1.25f), + rippleText, rippleStyle)) + { + ActiveWeaponManager.ToggleRippleFire(); + } + + rippleHeight = Mathf.Lerp(rippleHeight, 1.25f, 0.15f); + } + else + { + string rippleText = ActiveWeaponManager.rippleFire + ? Localizer.Format("#LOC_BDArmory_WMWindow_rippleText3", ActiveWeaponManager.rippleRPM.ToString("0"))//"Ripple: " + + " RPM" + : Localizer.Format("#LOC_BDArmory_WMWindow_rippleText4");//"Ripple: OFF" + GUIStyle rippleStyle = ActiveWeaponManager.rippleFire + ? BDGuiSkin.box + : BDGuiSkin.button; + if ( + GUI.Button( + new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 2, entryHeight * 1.25f), + rippleText, rippleStyle)) + { + ActiveWeaponManager.ToggleRippleFire(); + } + if (ActiveWeaponManager.rippleFire) + { + Rect sliderRect = new Rect(leftIndent + (contentWidth / 2) + 2, + contentTop + (line * entryHeight) + 6.5f, (contentWidth / 2) - 2, 12); + ActiveWeaponManager.rippleRPM = GUI.HorizontalSlider(sliderRect, + ActiveWeaponManager.rippleRPM, 100, 1600, rippleSliderStyle, rippleThumbStyle); + } + rippleHeight = Mathf.Lerp(rippleHeight, 1.25f, 0.15f); + } + } + else + { + rippleHeight = Mathf.Lerp(rippleHeight, 0, 0.15f); + } + //line += 1.25f; + line += rippleHeight; + line += 0.1f; + + if (!toolMinimized) + { + showWeaponList = + GUI.Toggle(new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 3, entryHeight), + showWeaponList, Localizer.Format("#LOC_BDArmory_WMWindow_ListWeapons"), showWeaponList ? BDGuiSkin.box : BDGuiSkin.button);//"Weapons" + showGuardMenu = + GUI.Toggle( + new Rect(leftIndent + (contentWidth / 3), contentTop + (line * entryHeight), contentWidth / 3, + entryHeight), showGuardMenu, Localizer.Format("#LOC_BDArmory_WMWindow_GuardMenu"),//"Guard Menu" + showGuardMenu ? BDGuiSkin.box : BDGuiSkin.button); + showModules = + GUI.Toggle( + new Rect(leftIndent + (2 * contentWidth / 3), contentTop + (line * entryHeight), contentWidth / 3, + entryHeight), showModules, Localizer.Format("#LOC_BDArmory_WMWindow_ModulesToggle"),//"Modules" + showModules ? BDGuiSkin.box : BDGuiSkin.button); + line++; + } + + float weaponLines = 0; + if (showWeaponList && !toolMinimized) + { + line += 0.25f; + Rect weaponListGroupRect = new Rect(5, contentTop + (line * entryHeight), toolWindowWidth - 10, + ((float)ActiveWeaponManager.weaponArray.Length + 0.1f) * entryHeight); + GUI.BeginGroup(weaponListGroupRect, GUIContent.none, BDGuiSkin.box); //darker box + weaponLines += 0.1f; + for (int i = 0; i < ActiveWeaponManager.weaponArray.Length; i++) + { + GUIStyle wpnListStyle; + GUIStyle tgtStyle; + if (i == ActiveWeaponManager.weaponIndex) + { + wpnListStyle = middleLeftLabelOrange; + tgtStyle = targetModeStyleSelected; + } + else + { + wpnListStyle = middleLeftLabel; + tgtStyle = targetModeStyle; + } + string label; + string subLabel; + if (ActiveWeaponManager.weaponArray[i] != null) + { + label = ActiveWeaponManager.weaponArray[i].GetShortName(); + subLabel = ActiveWeaponManager.weaponArray[i].GetSubLabel(); + } + else + { + label = Localizer.Format("#LOC_BDArmory_WMWindow_NoneWeapon");//"None" + subLabel = String.Empty; + } + Rect weaponButtonRect = new Rect(leftIndent, (weaponLines * entryHeight), + weaponListGroupRect.width - (2 * leftIndent), entryHeight); + + GUI.Label(weaponButtonRect, subLabel, tgtStyle); + + if (GUI.Button(weaponButtonRect, label, wpnListStyle)) + { + ActiveWeaponManager.CycleWeapon(i); + } + + if (i < ActiveWeaponManager.weaponArray.Length - 1) + { + BDGUIUtils.DrawRectangle( + new Rect(weaponButtonRect.x, weaponButtonRect.y + weaponButtonRect.height, + weaponButtonRect.width, 1), Color.white); + } + weaponLines++; + } + weaponLines += 0.1f; + GUI.EndGroup(); + } + weaponsHeight = Mathf.Lerp(weaponsHeight, weaponLines, 0.15f); + line += weaponsHeight; + + float guardLines = 0; + if (showGuardMenu && !toolMinimized) + { + line += 0.25f; + GUI.BeginGroup( + new Rect(5, contentTop + (line * entryHeight), toolWindowWidth - 10, 7.45f * entryHeight), + GUIContent.none, BDGuiSkin.box); + guardLines += 0.1f; + contentWidth -= 16; + leftIndent += 3; + string guardButtonLabel = Localizer.Format("#LOC_BDArmory_WMWindow_NoneWeapon", (ActiveWeaponManager.guardMode ? Localizer.Format("#LOC_BDArmory_Generic_On") : Localizer.Format("#LOC_BDArmory_Generic_Off")));//"Guard Mode " + "ON""Off" + if (GUI.Button(new Rect(leftIndent, (guardLines * entryHeight), contentWidth, entryHeight), + guardButtonLabel, ActiveWeaponManager.guardMode ? BDGuiSkin.box : BDGuiSkin.button)) + { + ActiveWeaponManager.ToggleGuardMode(); + } + guardLines += 1.25f; + + GUI.Label(new Rect(leftIndent, (guardLines * entryHeight), 85, entryHeight), Localizer.Format("#LOC_BDArmory_WMWindow_FiringInterval"), leftLabel);//"Firing Interval" + ActiveWeaponManager.targetScanInterval = + GUI.HorizontalSlider( + new Rect(leftIndent + (90), (guardLines * entryHeight), contentWidth - 90 - 38, entryHeight), + ActiveWeaponManager.targetScanInterval, 1, 60); + ActiveWeaponManager.targetScanInterval = Mathf.Round(ActiveWeaponManager.targetScanInterval); + GUI.Label(new Rect(leftIndent + (contentWidth - 35), (guardLines * entryHeight), 35, entryHeight), + ActiveWeaponManager.targetScanInterval.ToString(), leftLabel); + guardLines++; + + // extension for feature_engagementenvelope: set the firing burst length + string burstLabel = Localizer.Format("#LOC_BDArmory_WMWindow_BurstLength");//"Burst Length" + GUI.Label(new Rect(leftIndent, (guardLines * entryHeight), 85, entryHeight), burstLabel, leftLabel); + ActiveWeaponManager.fireBurstLength = + GUI.HorizontalSlider( + new Rect(leftIndent + (90), (guardLines * entryHeight), contentWidth - 90 - 38, entryHeight), + ActiveWeaponManager.fireBurstLength, 0, 60); + ActiveWeaponManager.fireBurstLength = Mathf.Round(ActiveWeaponManager.fireBurstLength * 2) / 2; + GUI.Label(new Rect(leftIndent + (contentWidth - 35), (guardLines * entryHeight), 35, entryHeight), + ActiveWeaponManager.fireBurstLength.ToString(), leftLabel); + guardLines++; + + GUI.Label(new Rect(leftIndent, (guardLines * entryHeight), 85, entryHeight), Localizer.Format("#LOC_BDArmory_WMWindow_FieldofView"),//"Field of View" + leftLabel); + float guardAngle = ActiveWeaponManager.guardAngle; + guardAngle = + GUI.HorizontalSlider( + new Rect(leftIndent + 90, (guardLines * entryHeight), contentWidth - 90 - 38, entryHeight), + guardAngle, 10, 360); + guardAngle = guardAngle / 10; + guardAngle = Mathf.Round(guardAngle); + ActiveWeaponManager.guardAngle = guardAngle * 10; + GUI.Label(new Rect(leftIndent + (contentWidth - 35), (guardLines * entryHeight), 35, entryHeight), + ActiveWeaponManager.guardAngle.ToString(), leftLabel); + guardLines++; + + GUI.Label(new Rect(leftIndent, (guardLines * entryHeight), 85, entryHeight), Localizer.Format("#LOC_BDArmory_WMWindow_VisualRange"), leftLabel);//"Visual Range" + float guardRange = ActiveWeaponManager.guardRange; + guardRange = + GUI.HorizontalSlider( + new Rect(leftIndent + 90, (guardLines * entryHeight), contentWidth - 90 - 38, entryHeight), + guardRange, 100, BDArmorySettings.MAX_GUARD_VISUAL_RANGE); + guardRange = guardRange / 100; + guardRange = Mathf.Round(guardRange); + ActiveWeaponManager.guardRange = guardRange * 100; + GUI.Label(new Rect(leftIndent + (contentWidth - 35), (guardLines * entryHeight), 35, entryHeight), + ActiveWeaponManager.guardRange.ToString(), leftLabel); + guardLines++; + + GUI.Label(new Rect(leftIndent, (guardLines * entryHeight), 85, entryHeight), Localizer.Format("#LOC_BDArmory_WMWindow_GunsRange"), leftLabel);//"Guns Range" + float gRange = ActiveWeaponManager.gunRange; + gRange = + GUI.HorizontalSlider( + new Rect(leftIndent + 90, (guardLines * entryHeight), contentWidth - 90 - 38, entryHeight), + gRange, 0, BDArmorySettings.MAX_BULLET_RANGE); + gRange /= 100f; + gRange = Mathf.Round(gRange); + gRange *= 100f; + ActiveWeaponManager.gunRange = gRange; + GUI.Label(new Rect(leftIndent + (contentWidth - 35), (guardLines * entryHeight), 35, entryHeight), + ActiveWeaponManager.gunRange.ToString(), leftLabel); + guardLines++; + + GUI.Label(new Rect(leftIndent, (guardLines * entryHeight), 85, entryHeight), Localizer.Format("#LOC_BDArmory_WMWindow_MissilesTgt"), leftLabel);//"Missiles/Tgt" + float mslCount = ActiveWeaponManager.maxMissilesOnTarget; + mslCount = + GUI.HorizontalSlider( + new Rect(leftIndent + 90, (guardLines * entryHeight), contentWidth - 90 - 38, entryHeight), + mslCount, 1, MissileFire.maxAllowableMissilesOnTarget); + mslCount = Mathf.Round(mslCount); + ActiveWeaponManager.maxMissilesOnTarget = mslCount; + GUI.Label(new Rect(leftIndent + (contentWidth - 35), (guardLines * entryHeight), 35, entryHeight), + ActiveWeaponManager.maxMissilesOnTarget.ToString(), leftLabel); + guardLines++; + + string targetType = Localizer.Format("#LOC_BDArmory_WMWindow_TargetType");//"Target Type: " + if (ActiveWeaponManager.targetMissiles) + { + targetType += Localizer.Format("#LOC_BDArmory_WMWindow_TargetType_Missiles");//"Missiles" + } + else + { + targetType += Localizer.Format("#LOC_BDArmory_WMWindow_TargetType_All");//"All Targets" + } + + if (GUI.Button(new Rect(leftIndent, (guardLines * entryHeight), contentWidth, entryHeight), targetType, + BDGuiSkin.button)) + { + ActiveWeaponManager.ToggleTargetType(); + } + guardLines++; + GUI.EndGroup(); + line += 0.1f; + } + guardHeight = Mathf.Lerp(guardHeight, guardLines, 0.15f); + line += guardHeight; + + float moduleLines = 0; + if (showModules && !toolMinimized) + { + line += 0.25f; + GUI.BeginGroup( + new Rect(5, contentTop + (line * entryHeight), toolWindowWidth - 10, numberOfModules * entryHeight), + GUIContent.none, BDGuiSkin.box); + + numberOfModules = 0; + moduleLines += 0.1f; + //RWR + if (ActiveWeaponManager.rwr) + { + numberOfModules++; + bool isEnabled = ActiveWeaponManager.rwr.displayRWR; + string label = Localizer.Format("#LOC_BDArmory_WMWindow_RadarWarning");//"Radar Warning Receiver" + Rect rwrRect = new Rect(leftIndent, +(moduleLines * entryHeight), contentWidth, entryHeight); + if (GUI.Button(rwrRect, label, isEnabled ? centerLabelOrange : centerLabel)) + { + if (isEnabled) + { + //ActiveWeaponManager.rwr.DisableRWR(); + ActiveWeaponManager.rwr.displayRWR = false; + } + else + { + //ActiveWeaponManager.rwr.EnableRWR(); + ActiveWeaponManager.rwr.displayRWR = true; + } + } + moduleLines++; + } + + //TGP + List.Enumerator mtc = ActiveWeaponManager.targetingPods.GetEnumerator(); + while (mtc.MoveNext()) + { + if (mtc.Current == null) continue; + numberOfModules++; + bool isEnabled = (mtc.Current.cameraEnabled); + bool isActive = (mtc.Current == ModuleTargetingCamera.activeCam); + GUIStyle moduleStyle = isEnabled ? centerLabelOrange : centerLabel; // = mtc + string label = mtc.Current.part.partInfo.title; + if (isActive) + { + moduleStyle = centerLabelRed; + label = "[" + label + "]"; + } + if (GUI.Button(new Rect(leftIndent, +(moduleLines * entryHeight), contentWidth, entryHeight), + label, moduleStyle)) + { + if (isActive) + { + mtc.Current.ToggleCamera(); + } + else + { + mtc.Current.EnableCamera(); + } + } + moduleLines++; + } + mtc.Dispose(); + + //RADAR + List.Enumerator mr = ActiveWeaponManager.radars.GetEnumerator(); + while (mr.MoveNext()) + { + if (mr.Current == null) continue; + numberOfModules++; + GUIStyle moduleStyle = mr.Current.radarEnabled ? centerLabelBlue : centerLabel; + string label = mr.Current.radarName; + if (GUI.Button(new Rect(leftIndent, +(moduleLines * entryHeight), contentWidth, entryHeight), + label, moduleStyle)) + { + mr.Current.Toggle(); + } + moduleLines++; + } + mr.Dispose(); + + //JAMMERS + List.Enumerator jammer = ActiveWeaponManager.jammers.GetEnumerator(); + while (jammer.MoveNext()) + { + if (jammer.Current == null) continue; + if (jammer.Current.alwaysOn) continue; + + numberOfModules++; + GUIStyle moduleStyle = jammer.Current.jammerEnabled ? centerLabelBlue : centerLabel; + string label = jammer.Current.part.partInfo.title; + if (GUI.Button(new Rect(leftIndent, +(moduleLines * entryHeight), contentWidth, entryHeight), + label, moduleStyle)) + { + jammer.Current.Toggle(); + } + moduleLines++; + } + jammer.Dispose(); + + //Other modules + using (var module = ActiveWeaponManager.wmModules.GetEnumerator()) + while (module.MoveNext()) + { + if (module.Current == null) continue; + + numberOfModules++; + GUIStyle moduleStyle = module.Current.Enabled ? centerLabelBlue : centerLabel; + string label = module.Current.Name; + if (GUI.Button(new Rect(leftIndent, +(moduleLines * entryHeight), contentWidth, entryHeight), + label, moduleStyle)) + { + module.Current.Toggle(); + } + moduleLines++; + } + + //GPS coordinator + GUIStyle gpsModuleStyle = showWindowGPS ? centerLabelBlue : centerLabel; + numberOfModules++; + if (GUI.Button(new Rect(leftIndent, +(moduleLines * entryHeight), contentWidth, entryHeight), + Localizer.Format("#LOC_BDArmory_WMWindow_GPSCoordinator"), gpsModuleStyle))//"GPS Coordinator" + { + showWindowGPS = !showWindowGPS; + } + moduleLines++; + + //wingCommander + if (ActiveWeaponManager.wingCommander) + { + GUIStyle wingComStyle = ActiveWeaponManager.wingCommander.showGUI + ? centerLabelBlue + : centerLabel; + numberOfModules++; + if (GUI.Button(new Rect(leftIndent, +(moduleLines * entryHeight), contentWidth, entryHeight), + Localizer.Format("#LOC_BDArmory_WMWindow_WingCommand"), wingComStyle))//"Wing Command" + { + ActiveWeaponManager.wingCommander.ToggleGUI(); + } + moduleLines++; + } + + GUI.EndGroup(); + + line += 0.1f; + } + modulesHeight = Mathf.Lerp(modulesHeight, moduleLines, 0.15f); + line += modulesHeight; + + float gpsLines = 0; + if (showWindowGPS && !toolMinimized) + { + line += 0.25f; + GUI.BeginGroup(new Rect(5, contentTop + (line * entryHeight), toolWindowWidth, WindowRectGps.height)); + WindowGPS(); + GUI.EndGroup(); + gpsLines = WindowRectGps.height / entryHeight; + } + gpsHeight = Mathf.Lerp(gpsHeight, gpsLines, 0.15f); + line += gpsHeight; + } + else + { + GUI.Label(new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth, entryHeight), + Localizer.Format("#LOC_BDArmory_WMWindow_NoWeaponManager"), BDGuiSkin.box);// "No Weapon Manager found." + line++; + } + + toolWindowHeight = Mathf.Lerp(toolWindowHeight, contentTop + (line * entryHeight) + 5, 1); + WindowRectToolbar.height = toolWindowHeight; + // = new Rect(toolbarWindowRect.position.x, toolbarWindowRect.position.y, toolWindowWidth, toolWindowHeight); + BDGUIUtils.RepositionWindow(ref WindowRectToolbar); + } + + bool validGPSName = true; + + //GPS window + public void WindowGPS() + { + GUI.Box(WindowRectGps, GUIContent.none, BDGuiSkin.box); + gpsEntryCount = 0; + Rect listRect = new Rect(gpsBorder, gpsBorder, WindowRectGps.width - (2 * gpsBorder), + WindowRectGps.height - (2 * gpsBorder)); + GUI.BeginGroup(listRect); + string targetLabel = Localizer.Format("#LOC_BDArmory_WMWindow_GPSTarget") + ": " + ActiveWeaponManager.designatedGPSInfo.name;//GPS Target + GUI.Label(new Rect(0, 0, listRect.width, gpsEntryHeight), targetLabel, kspTitleLabel); + + // Expand/Collapse Target Toggle button + if (GUI.Button(new Rect(listRect.width - gpsEntryHeight, 0, gpsEntryHeight, gpsEntryHeight), showTargets ? "-" : "+", BDGuiSkin.button)) + showTargets = !showTargets; + + gpsEntryCount += 0.85f; + if (ActiveWeaponManager.designatedGPSCoords != Vector3d.zero) + { + GUI.Label(new Rect(0, gpsEntryCount * gpsEntryHeight, listRect.width - gpsEntryHeight, gpsEntryHeight), + Misc.Misc.FormattedGeoPos(ActiveWeaponManager.designatedGPSCoords, true), BDGuiSkin.box); + if ( + GUI.Button( + new Rect(listRect.width - gpsEntryHeight, gpsEntryCount * gpsEntryHeight, gpsEntryHeight, + gpsEntryHeight), "X", BDGuiSkin.button)) + { + ActiveWeaponManager.designatedGPSInfo = new GPSTargetInfo(); + } + } + else + { + GUI.Label(new Rect(0, gpsEntryCount * gpsEntryHeight, listRect.width - gpsEntryHeight, gpsEntryHeight), + Localizer.Format("#LOC_BDArmory_WMWindow_NoTarget"), BDGuiSkin.box);//"No Target" + } + + gpsEntryCount += 1.35f; + int indexToRemove = -1; + int index = 0; + BDTeam myTeam = ActiveWeaponManager.Team; + if (showTargets) + { + List.Enumerator coordinate = BDATargetManager.GPSTargetList(myTeam).GetEnumerator(); + while (coordinate.MoveNext()) + { + Color origWColor = GUI.color; + if (coordinate.Current.EqualsTarget(ActiveWeaponManager.designatedGPSInfo)) + { + GUI.color = XKCDColors.LightOrange; + } + + string label = Misc.Misc.FormattedGeoPosShort(coordinate.Current.gpsCoordinates, false); + float nameWidth = 100; + if (editingGPSName && index == editingGPSNameIndex) + { + if (validGPSName && Event.current.type == EventType.KeyDown && + Event.current.keyCode == KeyCode.Return) + { + editingGPSName = false; + hasEnteredGPSName = true; + } + else + { + Color origColor = GUI.color; + if (newGPSName.Contains(";") || newGPSName.Contains(":") || newGPSName.Contains(",")) + { + validGPSName = false; + GUI.color = Color.red; + } + else + { + validGPSName = true; + } + + newGPSName = GUI.TextField( + new Rect(0, gpsEntryCount * gpsEntryHeight, nameWidth, gpsEntryHeight), newGPSName, 12); + GUI.color = origColor; + } + } + else + { + if (GUI.Button(new Rect(0, gpsEntryCount * gpsEntryHeight, nameWidth, gpsEntryHeight), + coordinate.Current.name, + BDGuiSkin.button)) + { + editingGPSName = true; + editingGPSNameIndex = index; + newGPSName = coordinate.Current.name; + } + } + + if ( + GUI.Button( + new Rect(nameWidth, gpsEntryCount * gpsEntryHeight, listRect.width - gpsEntryHeight - nameWidth, + gpsEntryHeight), label, BDGuiSkin.button)) + { + ActiveWeaponManager.designatedGPSInfo = coordinate.Current; + editingGPSName = false; + } + + if ( + GUI.Button( + new Rect(listRect.width - gpsEntryHeight, gpsEntryCount * gpsEntryHeight, gpsEntryHeight, + gpsEntryHeight), "X", BDGuiSkin.button)) + { + indexToRemove = index; + } + + gpsEntryCount++; + index++; + GUI.color = origWColor; + } + coordinate.Dispose(); + } + + if (hasEnteredGPSName && editingGPSNameIndex < BDATargetManager.GPSTargetList(myTeam).Count) + { + hasEnteredGPSName = false; + GPSTargetInfo old = BDATargetManager.GPSTargetList(myTeam)[editingGPSNameIndex]; + if (ActiveWeaponManager.designatedGPSInfo.EqualsTarget(old)) + { + ActiveWeaponManager.designatedGPSInfo.name = newGPSName; + } + BDATargetManager.GPSTargetList(myTeam)[editingGPSNameIndex] = + new GPSTargetInfo(BDATargetManager.GPSTargetList(myTeam)[editingGPSNameIndex].gpsCoordinates, + newGPSName); + editingGPSNameIndex = 0; + BDATargetManager.Instance.SaveGPSTargets(); + } + + GUI.EndGroup(); + + if (indexToRemove >= 0) + { + BDATargetManager.GPSTargetList(myTeam).RemoveAt(indexToRemove); + BDATargetManager.Instance.SaveGPSTargets(); + } + + WindowRectGps.height = (2 * gpsBorder) + (gpsEntryCount * gpsEntryHeight); + } + + Rect SLineRect(float line) + { + return new Rect(settingsMargin, line * settingsLineHeight, settingsWidth - (2 * settingsMargin), + settingsLineHeight); + } + + Rect SRightRect(float line) + { + return new Rect(settingsMargin + ((settingsWidth - 2 * settingsLineHeight) / 2), line * settingsLineHeight, + (settingsWidth - (2 * settingsMargin)) / 2, settingsLineHeight); + } + + Rect SLeftRect(float line) + { + return new Rect(settingsMargin, (line * settingsLineHeight), (settingsWidth - (2 * settingsMargin)) / 2, + settingsLineHeight); + } + + float settingsWidth; + float settingsHeight; + float settingsLeft; + float settingsTop; + float settingsLineHeight; + float settingsMargin; + + bool editKeys; + + void SetupSettingsSize() + { + settingsWidth = 420; + settingsHeight = 480; + settingsLeft = Screen.width / 2 - settingsWidth / 2; + settingsTop = 100; + settingsLineHeight = 22; + settingsMargin = 18; + WindowRectSettings = new Rect(settingsLeft, settingsTop, 420, 480); + } + + void WindowSettings(int windowID) + { + float line = 1.25f; + GUI.Box(new Rect(0, 0, settingsWidth, settingsHeight), Localizer.Format("#LOC_BDArmory_Settings_Title"));//"BDArmory Settings" + if (GUI.Button(new Rect(settingsWidth - 18, 2, 16, 16), "X")) + { + windowSettingsEnabled = false; + } + GUI.DragWindow(new Rect(0, 0, settingsWidth, 25)); + if (editKeys) + { + InputSettings(); + return; + } + BDArmorySettings.INSTAKILL = GUI.Toggle(SLeftRect(line), BDArmorySettings.INSTAKILL, Localizer.Format("#LOC_BDArmory_Settings_Instakill"));//"Instakill" + BDArmorySettings.INFINITE_AMMO = GUI.Toggle(SRightRect(line), BDArmorySettings.INFINITE_AMMO, Localizer.Format("#LOC_BDArmory_Settings_InfiniteAmmo"));//"Infinite Ammo" + line++; + BDArmorySettings.BULLET_HITS = GUI.Toggle(SLeftRect(line), BDArmorySettings.BULLET_HITS, Localizer.Format("#LOC_BDArmory_Settings_BulletHits"));//"Bullet Hits" + BDArmorySettings.EJECT_SHELLS = GUI.Toggle(SRightRect(line), BDArmorySettings.EJECT_SHELLS, Localizer.Format("#LOC_BDArmory_Settings_EjectShells"));//"Eject Shells" + line++; + BDArmorySettings.AIM_ASSIST = GUI.Toggle(SLeftRect(line), BDArmorySettings.AIM_ASSIST, Localizer.Format("#LOC_BDArmory_Settings_AimAssist"));//"Aim Assist" + BDArmorySettings.DRAW_AIMERS = GUI.Toggle(SRightRect(line), BDArmorySettings.DRAW_AIMERS, Localizer.Format("#LOC_BDArmory_Settings_DrawAimers"));//"Draw Aimers" + line++; + BDArmorySettings.DRAW_DEBUG_LINES = GUI.Toggle(SLeftRect(line), BDArmorySettings.DRAW_DEBUG_LINES, Localizer.Format("#LOC_BDArmory_Settings_DebugLines"));//"Debug Lines" + BDArmorySettings.DRAW_DEBUG_LABELS = GUI.Toggle(SRightRect(line), BDArmorySettings.DRAW_DEBUG_LABELS, Localizer.Format("#LOC_BDArmory_Settings_DebugLabels"));//"Debug Labels" + line++; + BDArmorySettings.REMOTE_SHOOTING = GUI.Toggle(SLeftRect(line), BDArmorySettings.REMOTE_SHOOTING, Localizer.Format("#LOC_BDArmory_Settings_RemoteFiring"));//"Remote Firing" + BDArmorySettings.BOMB_CLEARANCE_CHECK = GUI.Toggle(SRightRect(line), BDArmorySettings.BOMB_CLEARANCE_CHECK, Localizer.Format("#LOC_BDArmory_Settings_ClearanceCheck"));//"Clearance Check" + line++; + BDArmorySettings.SHOW_AMMO_GAUGES = GUI.Toggle(SLeftRect(line), BDArmorySettings.SHOW_AMMO_GAUGES, Localizer.Format("#LOC_BDArmory_Settings_AmmoGauges"));//"Ammo Gauges" + BDArmorySettings.SHELL_COLLISIONS = GUI.Toggle(SRightRect(line), BDArmorySettings.SHELL_COLLISIONS, Localizer.Format("#LOC_BDArmory_Settings_ShellCollisions"));//"Shell Collisions" + line++; + BDArmorySettings.BULLET_DECALS = GUI.Toggle(SLeftRect(line), BDArmorySettings.BULLET_DECALS, Localizer.Format("#LOC_BDArmory_Settings_BulletHoleDecals"));//"Bullet Hole Decals" + BDArmorySettings.PERFORMANCE_LOGGING = GUI.Toggle(SRightRect(line), BDArmorySettings.PERFORMANCE_LOGGING, Localizer.Format("#LOC_BDArmory_Settings_PerformanceLogging"));//"Performance Logging" + line++; + if (HighLogic.LoadedSceneIsEditor) + { + if (BDArmorySettings.SHOW_CATEGORIES != (BDArmorySettings.SHOW_CATEGORIES = GUI.Toggle(SLeftRect(line), BDArmorySettings.SHOW_CATEGORIES, Localizer.Format("#LOC_BDArmory_Settings_ShowEditorSubcategories"))))//"Show Editor Subcategories" + { + KSP.UI.Screens.PartCategorizer.Instance.editorPartList.Refresh(); + } + if (BDArmorySettings.AUTOCATEGORIZE_PARTS != (BDArmorySettings.AUTOCATEGORIZE_PARTS = GUI.Toggle(SRightRect(line), BDArmorySettings.AUTOCATEGORIZE_PARTS, Localizer.Format("#LOC_BDArmory_Settings_AutocategorizeParts"))))//"Autocategorize Parts" + { + KSP.UI.Screens.PartCategorizer.Instance.editorPartList.Refresh(); + } + line++; + } + GUI.Label(SLeftRect(line), $"{Localizer.Format("#LOC_BDArmory_Settings_MaxBulletHoles")}: ({BDArmorySettings.MAX_NUM_BULLET_DECALS})", leftLabel);//Max Bullet Holes + BDArmorySettings.MAX_NUM_BULLET_DECALS = (int)GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.MAX_NUM_BULLET_DECALS, 1f, 999); + line++; + line++; + + bool origPm = BDArmorySettings.PEACE_MODE; + BDArmorySettings.PEACE_MODE = GUI.Toggle(SLeftRect(line), BDArmorySettings.PEACE_MODE, Localizer.Format("#LOC_BDArmory_Settings_PeaceMode"));//"Peace Mode" + if (BDArmorySettings.PEACE_MODE && !origPm) + { + BDATargetManager.ClearDatabase(); + if (OnPeaceEnabled != null) + { + OnPeaceEnabled(); + } + } + line++; + line++; + + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_RWRWindowScale") + ": " + (BDArmorySettings.RWR_WINDOW_SCALE * 100).ToString("0") + "%", leftLabel);//RWR Window Scale + float rwrScale = BDArmorySettings.RWR_WINDOW_SCALE; + rwrScale = Mathf.Round(GUI.HorizontalSlider(SRightRect(line), rwrScale, BDArmorySettings.RWR_WINDOW_SCALE_MIN, BDArmorySettings.RWR_WINDOW_SCALE_MAX) * 100.0f) * 0.01f; + if (rwrScale.ToString(CultureInfo.InvariantCulture) != BDArmorySettings.RWR_WINDOW_SCALE.ToString(CultureInfo.InvariantCulture)) + { + ResizeRwrWindow(rwrScale); + } + line++; + + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_RadarWindowScale") + ": " + (BDArmorySettings.RADAR_WINDOW_SCALE * 100).ToString("0") + "%", leftLabel);//Radar Window Scale + float radarScale = BDArmorySettings.RADAR_WINDOW_SCALE; + radarScale = Mathf.Round(GUI.HorizontalSlider(SRightRect(line), radarScale, BDArmorySettings.RADAR_WINDOW_SCALE_MIN, BDArmorySettings.RADAR_WINDOW_SCALE_MAX) * 100.0f) * 0.01f; + if (radarScale.ToString(CultureInfo.InvariantCulture) != BDArmorySettings.RADAR_WINDOW_SCALE.ToString(CultureInfo.InvariantCulture)) + { + ResizeRadarWindow(radarScale); + } + line++; + + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_TargetWindowScale") + ": " + (BDArmorySettings.TARGET_WINDOW_SCALE * 100).ToString("0") + "%", leftLabel);//Target Window Scale + float targetScale = BDArmorySettings.TARGET_WINDOW_SCALE; + targetScale = Mathf.Round(GUI.HorizontalSlider(SRightRect(line), targetScale, BDArmorySettings.TARGET_WINDOW_SCALE_MIN, BDArmorySettings.TARGET_WINDOW_SCALE_MAX) * 100.0f) * 0.01f; + if (targetScale.ToString(CultureInfo.InvariantCulture) != BDArmorySettings.TARGET_WINDOW_SCALE.ToString(CultureInfo.InvariantCulture)) + { + ResizeTargetWindow(targetScale); + } + line++; + line++; + + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_TriggerHold") + ": " + BDArmorySettings.TRIGGER_HOLD_TIME.ToString("0.00") + "s", leftLabel);//Trigger Hold + BDArmorySettings.TRIGGER_HOLD_TIME = GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.TRIGGER_HOLD_TIME, 0.02f, 1f); + line++; + + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_UIVolume") + ": " + (BDArmorySettings.BDARMORY_UI_VOLUME * 100).ToString("0"), leftLabel);//UI Volume + float uiVol = BDArmorySettings.BDARMORY_UI_VOLUME; + uiVol = GUI.HorizontalSlider(SRightRect(line), uiVol, 0f, 1f); + if (uiVol != BDArmorySettings.BDARMORY_UI_VOLUME && OnVolumeChange != null) + { + OnVolumeChange(); + } + BDArmorySettings.BDARMORY_UI_VOLUME = uiVol; + line++; + + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_WeaponVolume") + ": " + (BDArmorySettings.BDARMORY_WEAPONS_VOLUME * 100).ToString("0"), leftLabel);//Weapon Volume + float weaponVol = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; + weaponVol = GUI.HorizontalSlider(SRightRect(line), weaponVol, 0f, 1f); + if (uiVol != BDArmorySettings.BDARMORY_WEAPONS_VOLUME && OnVolumeChange != null) + { + OnVolumeChange(); + } + BDArmorySettings.BDARMORY_WEAPONS_VOLUME = weaponVol; + line++; + line++; + + //competition mode + if (HighLogic.LoadedSceneIsFlight) + { + GUI.Label(SLineRect(line), "= " + Localizer.Format("#LOC_BDArmory_Settings_DogfightCompetition") + " =", centerLabel);//Dogfight Competition + line++; + if (!BDACompetitionMode.Instance.competitionStarting) + { + compDistGui = GUI.TextField(SRightRect(line), compDistGui); + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_CompetitionDistance"));//"Competition Distance" + float cDist; + if (Single.TryParse(compDistGui, out cDist)) + { + competitionDist = cDist; + } + line++; + + if (GUI.Button(SRightRect(line), Localizer.Format("#LOC_BDArmory_Settings_StartCompetition")))//"Start Competition" + { + competitionDist = Mathf.Max(competitionDist, 0); + compDistGui = competitionDist.ToString(); + BDACompetitionMode.Instance.StartCompetitionMode(competitionDist); + SaveConfig(); + windowSettingsEnabled = false; + } + } + else + { + GUI.Label(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Settings_CompetitionStarting") + " (" + compDistGui + ")");//Starting Competition... + line++; + if (GUI.Button(SLeftRect(line), Localizer.Format("#LOC_BDArmory_Generic_Cancel")))//"Cancel" + { + BDACompetitionMode.Instance.StopCompetition(); + } + } + } + + line++; + line++; + if (GUI.Button(SLineRect(line), Localizer.Format("#LOC_BDArmory_Settings_EditInputs")))//"Edit Inputs" + { + editKeys = true; + } + line++; + line++; + if (!BDKeyBinder.current && GUI.Button(SLineRect(line), Localizer.Format("#LOC_BDArmory_Generic_SaveandClose")))//"Save and Close" + { + SaveConfig(); + windowSettingsEnabled = false; + } + + line += 1.5f; + settingsHeight = (line * settingsLineHeight); + WindowRectSettings.height = settingsHeight; + BDGUIUtils.RepositionWindow(ref WindowRectSettings); + BDGUIUtils.UseMouseEventInRect(WindowRectSettings); + } + + internal static void ResizeRwrWindow(float rwrScale) + { + BDArmorySettings.RWR_WINDOW_SCALE = rwrScale; + RadarWarningReceiver.RwrDisplayRect = new Rect(0, 0, RadarWarningReceiver.RwrSize * rwrScale, + RadarWarningReceiver.RwrSize * rwrScale); + BDArmorySetup.WindowRectRwr = + new Rect(BDArmorySetup.WindowRectRwr.x, BDArmorySetup.WindowRectRwr.y, + RadarWarningReceiver.RwrDisplayRect.height + RadarWarningReceiver.BorderSize, + RadarWarningReceiver.RwrDisplayRect.height + RadarWarningReceiver.BorderSize + RadarWarningReceiver.HeaderSize); + } + + internal static void ResizeRadarWindow(float radarScale) + { + BDArmorySettings.RADAR_WINDOW_SCALE = radarScale; + VesselRadarData.RadarDisplayRect = + new Rect(VesselRadarData.BorderSize / 2, VesselRadarData.BorderSize / 2 + VesselRadarData.HeaderSize, + VesselRadarData.RadarScreenSize * radarScale, + VesselRadarData.RadarScreenSize * radarScale); + WindowRectRadar = + new Rect(WindowRectRadar.x, WindowRectRadar.y, + VesselRadarData.RadarDisplayRect.height + VesselRadarData.BorderSize + VesselRadarData.ControlsWidth + VesselRadarData.Gap * 3, + VesselRadarData.RadarDisplayRect.height + VesselRadarData.BorderSize + VesselRadarData.HeaderSize); + } + + internal static void ResizeTargetWindow(float targetScale) + { + BDArmorySettings.TARGET_WINDOW_SCALE = targetScale; + ModuleTargetingCamera.ResizeTargetWindow(); + } + + private static Vector2 _displayViewerPosition = Vector2.zero; + + void InputSettings() + { + float line = 1.25f; + int inputID = 0; + float origSettingsWidth = settingsWidth; + float origSettingsHeight = settingsHeight; + float origSettingsMargin = settingsMargin; + + settingsWidth = origSettingsWidth - 28; + settingsMargin = 10; + Rect viewRect = new Rect(settingsMargin, 20, origSettingsWidth - 12, origSettingsHeight - 100); + Rect scrollerRect = new Rect(settingsMargin, 20, origSettingsWidth - 30, settingsHeight * 1.4f); + + _displayViewerPosition = GUI.BeginScrollView(viewRect, _displayViewerPosition, scrollerRect, false, true); + + GUI.Label(SLineRect(line), "- " + Localizer.Format("#LOC_BDArmory_InputSettings_Weapons") + " -", centerLabel);//Weapons + line++; + InputSettingsList("WEAP_", ref inputID, ref line); + line++; + + GUI.Label(SLineRect(line), "- "+Localizer.Format("#LOC_BDArmory_InputSettings_TargetingPod") +" -", centerLabel);//Targeting Pod + line++; + InputSettingsList("TGP_", ref inputID, ref line); + line++; + + GUI.Label(SLineRect(line), "- "+Localizer.Format("#LOC_BDArmory_InputSettings_Radar") +" -", centerLabel);//Radar + line++; + InputSettingsList("RADAR_", ref inputID, ref line); + line++; + + GUI.Label(SLineRect(line), "- "+Localizer.Format("#LOC_BDArmory_InputSettings_VesselSwitcher") +" -", centerLabel);//Vessel Switcher + line++; + InputSettingsList("VS_", ref inputID, ref line); + GUI.EndScrollView(); + + line = (origSettingsHeight - 100) / settingsLineHeight; + line += 2; + settingsWidth = origSettingsWidth; + settingsMargin = origSettingsMargin; + if (!BDKeyBinder.current && GUI.Button(SLineRect(line), Localizer.Format("#LOC_BDArmory_InputSettings_BackBtn")))//"Back" + { + editKeys = false; + } + + //line += 1.5f; + settingsHeight = origSettingsHeight; + WindowRectSettings.height = origSettingsHeight; + BDGUIUtils.UseMouseEventInRect(WindowRectSettings); + } + + void InputSettingsList(string prefix, ref int id, ref float line) + { + if (inputFields != null) + { + for (int i = 0; i < inputFields.Length; i++) + { + string fieldName = inputFields[i].Name; + if (fieldName.StartsWith(prefix, StringComparison.Ordinal)) + { + InputSettingsLine(fieldName, id++, ref line); + } + } + } + } + + void InputSettingsLine(string fieldName, int id, ref float line) + { + GUI.Box(SLineRect(line), GUIContent.none); + string label = String.Empty; + if (BDKeyBinder.IsRecordingID(id)) + { + string recordedInput; + if (BDKeyBinder.current.AcquireInputString(out recordedInput)) + { + BDInputInfo orig = (BDInputInfo)typeof(BDInputSettingsFields).GetField(fieldName).GetValue(null); + BDInputInfo recorded = new BDInputInfo(recordedInput, orig.description); + typeof(BDInputSettingsFields).GetField(fieldName).SetValue(null, recorded); + } + + label = " " + Localizer.Format("#LOC_BDArmory_InputSettings_recordedInput");//Press a key or button. + } + else + { + BDInputInfo inputInfo = new BDInputInfo(); + try + { + inputInfo = (BDInputInfo)typeof(BDInputSettingsFields).GetField(fieldName).GetValue(null); + } + catch (NullReferenceException) + { + Debug.Log("[BDArmory]: Reflection failed to find input info of field: " + fieldName); + editKeys = false; + return; + } + label = " " + inputInfo.description + " : " + inputInfo.inputString; + + if (GUI.Button(SSetKeyRect(line), Localizer.Format("#LOC_BDArmory_InputSettings_SetKey")))//"Set Key" + { + BDKeyBinder.BindKey(id); + } + if (GUI.Button(SClearKeyRect(line), Localizer.Format("#LOC_BDArmory_InputSettings_Clear")))//"Clear" + { + typeof(BDInputSettingsFields).GetField(fieldName) + .SetValue(null, new BDInputInfo(inputInfo.description)); + } + } + GUI.Label(SLeftRect(line), label); + line++; + } + + Rect SSetKeyRect(float line) + { + return new Rect(settingsMargin + (2 * (settingsWidth - 2 * settingsMargin) / 3), line * settingsLineHeight, + (settingsWidth - (2 * settingsMargin)) / 6, settingsLineHeight); + } + + Rect SClearKeyRect(float line) + { + return + new Rect( + settingsMargin + (2 * (settingsWidth - 2 * settingsMargin) / 3) + (settingsWidth - 2 * settingsMargin) / 6, + line * settingsLineHeight, (settingsWidth - (2 * settingsMargin)) / 6, settingsLineHeight); + } + + #endregion GUI + + void HideGameUI() + { + GAME_UI_ENABLED = false; + } + + void ShowGameUI() + { + GAME_UI_ENABLED = true; + } + + internal void OnDestroy() + { + if (maySavethisInstance) + { + BDAWindowSettingsField.Save(); + } + + GameEvents.onHideUI.Remove(HideGameUI); + GameEvents.onShowUI.Remove(ShowGameUI); + GameEvents.onVesselGoOffRails.Remove(OnVesselGoOffRails); + GameEvents.OnGameSettingsApplied.Remove(SaveVolumeSettings); + GameEvents.onVesselChange.Remove(VesselChange); + } + + void OnVesselGoOffRails(Vessel v) + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + Debug.Log("[BDArmory]: Loaded vessel: " + v.vesselName + ", Velocity: " + v.Velocity() + ", packed: " + v.packed); + //v.SetWorldVelocity(Vector3d.zero); + } + } + + public void SaveVolumeSettings() + { + SeismicChargeFX.originalShipVolume = GameSettings.SHIP_VOLUME; + SeismicChargeFX.originalMusicVolume = GameSettings.MUSIC_VOLUME; + SeismicChargeFX.originalAmbienceVolume = GameSettings.AMBIENCE_VOLUME; + } + } +} diff --git a/BDArmory/UI/BDGUIComboBox.cs b/BDArmory/UI/BDGUIComboBox.cs new file mode 100644 index 000000000..52a8588ae --- /dev/null +++ b/BDArmory/UI/BDGUIComboBox.cs @@ -0,0 +1,112 @@ +using UnityEngine; + +namespace BDArmory.UI +{ + public class BDGUIComboBox + { + private static bool forceToUnShow = false; + private static int useControlID = -1; + private bool isClickedComboButton = false; + private int selectedItemIndex = -1; + + private Rect rect; + private Rect buttonRect; + private GUIContent buttonContent; + private GUIContent[] listContent; + private GUIStyle listStyle; + private Vector2 scrollViewVector; + private float comboxbox_height; + + public BDGUIComboBox(Rect rect, Rect buttonRect, GUIContent buttonContent, GUIContent[] listContent, float combo_height, GUIStyle listStyle) + { + this.rect = rect; + this.buttonRect = buttonRect; + this.buttonContent = buttonContent; + this.listContent = listContent; + this.listStyle = listStyle; + this.listStyle.active.textColor = Color.black; + this.listStyle.hover.textColor = Color.black; + this.comboxbox_height = combo_height; + } + + public int Show() + { + if (forceToUnShow) + { + forceToUnShow = false; + isClickedComboButton = false; + } + + bool done = false; + int controlID = GUIUtility.GetControlID(FocusType.Passive); + + switch (Event.current.GetTypeForControl(controlID)) + { + case EventType.MouseUp: + { + if (isClickedComboButton) + { + done = true; + } + } + break; + } + + if (selectedItemIndex > -1) + buttonContent.text = listContent[selectedItemIndex].text; + + if (GUI.Button(buttonRect, buttonContent, BDArmorySetup.BDGuiSkin.button)) + { + if (useControlID == -1) + { + useControlID = controlID; + isClickedComboButton = false; + } + + if (useControlID != controlID) + { + forceToUnShow = true; + useControlID = controlID; + } + isClickedComboButton = true; + } + + if (isClickedComboButton) + { + float items_height = listStyle.CalcHeight(listContent[0], 1.0f) * (listContent.Length + 5); + Rect listRect = new Rect(rect.x + 5, rect.y + listStyle.CalcHeight(listContent[0], 1.0f), rect.width - 20f, items_height); + + scrollViewVector = GUI.BeginScrollView(new Rect(rect.x, rect.y + rect.height, rect.width + 10f, comboxbox_height), scrollViewVector, + new Rect(rect.x, rect.y, rect.width - 10, items_height + rect.height), false, false, BDArmorySetup.BDGuiSkin.horizontalScrollbar, BDArmorySetup.BDGuiSkin.verticalScrollbar); + + GUI.Box(new Rect(rect.x, rect.y, rect.width - 10, items_height + rect.height), "", BDArmorySetup.BDGuiSkin.window); + + int newSelectedItemIndex = GUI.SelectionGrid(listRect, selectedItemIndex, listContent, 2, listStyle); + if (newSelectedItemIndex != selectedItemIndex) + { + selectedItemIndex = newSelectedItemIndex; + done = true; + } + + GUI.EndScrollView(); + } + + if (done) + isClickedComboButton = false; + + return selectedItemIndex; + } + + public int SelectedItemIndex + { + get + { + return selectedItemIndex; + } + set + { + selectedItemIndex = value; + } + } + } +} diff --git a/BDArmory/UI/BDGUIUtils.cs b/BDArmory/UI/BDGUIUtils.cs new file mode 100644 index 000000000..4afc23325 --- /dev/null +++ b/BDArmory/UI/BDGUIUtils.cs @@ -0,0 +1,184 @@ +using UnityEngine; +using Random = UnityEngine.Random; + +namespace BDArmory.UI +{ + public static class BDGUIUtils + { + public static Texture2D pixel; + + public static Camera GetMainCamera() + { + if (HighLogic.LoadedSceneIsFlight) + { + return FlightCamera.fetch.mainCamera; + } + else + { + return Camera.main; + } + } + + public static void DrawTextureOnWorldPos(Vector3 worldPos, Texture texture, Vector2 size, float wobble) + { + Vector3 screenPos = GetMainCamera().WorldToViewportPoint(worldPos); + if (screenPos.z < 0) return; //don't draw if point is behind camera + if (screenPos.x != Mathf.Clamp01(screenPos.x)) return; //don't draw if off screen + if (screenPos.y != Mathf.Clamp01(screenPos.y)) return; + float xPos = screenPos.x * Screen.width - (0.5f * size.x); + float yPos = (1 - screenPos.y) * Screen.height - (0.5f * size.y); + if (wobble > 0) + { + xPos += Random.Range(-wobble / 2, wobble / 2); + yPos += Random.Range(-wobble / 2, wobble / 2); + } + Rect iconRect = new Rect(xPos, yPos, size.x, size.y); + + GUI.DrawTexture(iconRect, texture); + } + + public static bool WorldToGUIPos(Vector3 worldPos, out Vector2 guiPos) + { + Vector3 screenPos = GetMainCamera().WorldToViewportPoint(worldPos); + bool offScreen = false; + if (screenPos.z < 0) offScreen = true; //dont draw if point is behind camera + if (screenPos.x != Mathf.Clamp01(screenPos.x)) offScreen = true; //dont draw if off screen + if (screenPos.y != Mathf.Clamp01(screenPos.y)) offScreen = true; + if (!offScreen) + { + float xPos = screenPos.x * Screen.width; + float yPos = (1 - screenPos.y) * Screen.height; + guiPos = new Vector2(xPos, yPos); + return true; + } + else + { + guiPos = Vector2.zero; + return false; + } + } + + public static void DrawLineBetweenWorldPositions(Vector3 worldPosA, Vector3 worldPosB, float width, Color color) + { + Camera cam = GetMainCamera(); + + if (cam == null) return; + + GUI.matrix = Matrix4x4.identity; + + bool aBehind = false; + + Plane clipPlane = new Plane(cam.transform.forward, cam.transform.position + cam.transform.forward * 0.05f); + + if (Vector3.Dot(cam.transform.forward, worldPosA - cam.transform.position) < 0) + { + Ray ray = new Ray(worldPosB, worldPosA - worldPosB); + float dist; + if (clipPlane.Raycast(ray, out dist)) + { + worldPosA = ray.GetPoint(dist); + } + aBehind = true; + } + if (Vector3.Dot(cam.transform.forward, worldPosB - cam.transform.position) < 0) + { + if (aBehind) return; + + Ray ray = new Ray(worldPosA, worldPosB - worldPosA); + float dist; + if (clipPlane.Raycast(ray, out dist)) + { + worldPosB = ray.GetPoint(dist); + } + } + + Vector3 screenPosA = cam.WorldToViewportPoint(worldPosA); + screenPosA.x = screenPosA.x * Screen.width; + screenPosA.y = (1 - screenPosA.y) * Screen.height; + Vector3 screenPosB = cam.WorldToViewportPoint(worldPosB); + screenPosB.x = screenPosB.x * Screen.width; + screenPosB.y = (1 - screenPosB.y) * Screen.height; + + screenPosA.z = screenPosB.z = 0; + + float angle = Vector2.Angle(Vector3.up, screenPosB - screenPosA); + if (screenPosB.x < screenPosA.x) + { + angle = -angle; + } + + Vector2 vector = screenPosB - screenPosA; + float length = vector.magnitude; + + Rect upRect = new Rect(screenPosA.x - (width / 2), screenPosA.y - length, width, length); + + GUIUtility.RotateAroundPivot(-angle + 180, screenPosA); + DrawRectangle(upRect, color); + GUI.matrix = Matrix4x4.identity; + } + + public static void DrawRectangle(Rect rect, Color color) + { + if (pixel == null) + { + pixel = new Texture2D(1, 1); + } + + Color originalColor = GUI.color; + GUI.color = color; + GUI.DrawTexture(rect, pixel); + GUI.color = originalColor; + } + + public static void MarkPosition(Transform transform, Color color) => MarkPosition(transform.position, transform, color); + + public static void MarkPosition(Vector3 position, Transform transform, Color color, float size = 3, float thickness = 2) + { + DrawLineBetweenWorldPositions(position + transform.right * size, position - transform.right * size, thickness, color); + DrawLineBetweenWorldPositions(position + transform.up * size, position - transform.up * size, thickness, color); + DrawLineBetweenWorldPositions(position + transform.forward * size, position - transform.forward * size, thickness, color); + } + + public static void UseMouseEventInRect(Rect rect) + { + if (Misc.Misc.MouseIsInRect(rect) && Event.current.isMouse && (Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseUp)) + { + Event.current.Use(); + } + } + + public static Rect CleanRectVals(Rect rect) + { + // Remove decimal places so Mac does not complain. + rect.x = (int)rect.x; + rect.y = (int)rect.y; + rect.width = (int)rect.width; + rect.height = (int)rect.height; + return rect; + } + + internal static void RepositionWindow(ref Rect windowPosition) + { + // This method uses Gui point system. + if (windowPosition.x < 0) windowPosition.x = 0; + if (windowPosition.y < 0) windowPosition.y = 0; + + if (windowPosition.xMax > Screen.width) + windowPosition.x = Screen.width - windowPosition.width; + if (windowPosition.yMax > Screen.height) + windowPosition.y = Screen.height - windowPosition.height; + } + + internal static Rect GuiToScreenRect(Rect rect) + { + // Must run during OnGui to work... + Rect newRect = new Rect + { + position = GUIUtility.GUIToScreenPoint(rect.position), + width = rect.width, + height = rect.height + }; + return newRect; + } + } +} diff --git a/BDArmory/UI/BDInputInfo.cs b/BDArmory/UI/BDInputInfo.cs new file mode 100644 index 000000000..f864ec432 --- /dev/null +++ b/BDArmory/UI/BDInputInfo.cs @@ -0,0 +1,20 @@ +namespace BDArmory.UI +{ + public struct BDInputInfo + { + public string description; + public string inputString; + + public BDInputInfo(string description) + { + this.description = description; + inputString = string.Empty; + } + + public BDInputInfo(string inputString, string description) + { + this.inputString = inputString; + this.description = description; + } + } +} diff --git a/BDArmory/UI/BDInputSettingsFields.cs b/BDArmory/UI/BDInputSettingsFields.cs new file mode 100644 index 000000000..ffa478b76 --- /dev/null +++ b/BDArmory/UI/BDInputSettingsFields.cs @@ -0,0 +1,89 @@ +using System.Reflection; +using BDArmory.Core; + +namespace BDArmory.UI +{ + public class BDInputSettingsFields + { + //MAIN + public static BDInputInfo WEAP_FIRE_KEY = new BDInputInfo("mouse 0", "Fire"); + + //TGP + public static BDInputInfo TGP_SLEW_RIGHT = new BDInputInfo("Slew Right"); + public static BDInputInfo TGP_SLEW_LEFT = new BDInputInfo("Slew Left"); + public static BDInputInfo TGP_SLEW_UP = new BDInputInfo("Slew Up"); + public static BDInputInfo TGP_SLEW_DOWN = new BDInputInfo("Slew Down"); + public static BDInputInfo TGP_LOCK = new BDInputInfo("Lock/Unlock"); + public static BDInputInfo TGP_IN = new BDInputInfo("Zoom In"); + public static BDInputInfo TGP_OUT = new BDInputInfo("Zoom Out"); + public static BDInputInfo TGP_RADAR = new BDInputInfo("To Radar"); + public static BDInputInfo TGP_SEND_GPS = new BDInputInfo("Send GPS"); + public static BDInputInfo TGP_TO_GPS = new BDInputInfo("Slave to GPS"); + public static BDInputInfo TGP_TURRETS = new BDInputInfo("Slave Turrets"); + public static BDInputInfo TGP_COM = new BDInputInfo("CoM-Track"); + public static BDInputInfo TGP_NV = new BDInputInfo("Toggle NV"); + public static BDInputInfo TGP_RESET = new BDInputInfo("Reset"); + + //RADAR + public static BDInputInfo RADAR_LOCK = new BDInputInfo("Lock/Unlock"); + public static BDInputInfo RADAR_CYCLE_LOCK = new BDInputInfo("Cycle Lock"); + public static BDInputInfo RADAR_SLEW_RIGHT = new BDInputInfo("Slew Right"); + public static BDInputInfo RADAR_SLEW_LEFT = new BDInputInfo("Slew Left"); + public static BDInputInfo RADAR_SLEW_UP = new BDInputInfo("Slew Up"); + public static BDInputInfo RADAR_SLEW_DOWN = new BDInputInfo("Slew Down"); + public static BDInputInfo RADAR_SCAN_MODE = new BDInputInfo("Scan Mode"); + public static BDInputInfo RADAR_TURRETS = new BDInputInfo("Slave Turrets"); + public static BDInputInfo RADAR_RANGE_UP = new BDInputInfo("Range +"); + public static BDInputInfo RADAR_RANGE_DN = new BDInputInfo("Range -"); + public static BDInputInfo RADAR_TARGET_NEXT = new BDInputInfo("Next Target"); + public static BDInputInfo RADAR_TARGET_PREV = new BDInputInfo("Prev Target"); + + // VESSEL SWITCHER + public static BDInputInfo VS_SWITCH_NEXT = new BDInputInfo("Next Vessel"); + public static BDInputInfo VS_SWITCH_PREV = new BDInputInfo("Prev Vessel"); + + public static void SaveSettings() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + if (!fileNode.HasNode("BDAInputSettings")) + { + fileNode.AddNode("BDAInputSettings"); + } + + ConfigNode cfg = fileNode.GetNode("BDAInputSettings"); + + FieldInfo[] fields = typeof(BDInputSettingsFields).GetFields(); + for (int i = 0; i < fields.Length; i++) + { + string fieldName = fields[i].Name; + string valueString = ((BDInputInfo)fields[i].GetValue(null)).inputString; + cfg.SetValue(fieldName, valueString, true); + } + + fileNode.Save(BDArmorySettings.settingsConfigURL); + } + + public static void LoadSettings() + { + ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); + if (!fileNode.HasNode("BDAInputSettings")) + { + fileNode.AddNode("BDAInputSettings"); + } + + ConfigNode cfg = fileNode.GetNode("BDAInputSettings"); + + FieldInfo[] fields = typeof(BDInputSettingsFields).GetFields(); + for (int i = 0; i < fields.Length; i++) + { + string fieldName = fields[i].Name; + if (!cfg.HasValue(fieldName)) continue; + BDInputInfo orig = (BDInputInfo)fields[i].GetValue(null); + BDInputInfo loaded = new BDInputInfo(cfg.GetValue(fieldName), orig.description); + fields[i].SetValue(null, loaded); + } + + fileNode.Save(BDArmorySettings.settingsConfigURL); + } + } +} diff --git a/BDArmory/UI/BDInputUtils.cs b/BDArmory/UI/BDInputUtils.cs new file mode 100644 index 000000000..c49e5143b --- /dev/null +++ b/BDArmory/UI/BDInputUtils.cs @@ -0,0 +1,161 @@ +using UnityEngine; + +namespace BDArmory.UI +{ + public class BDInputUtils + { + public static string GetInputString() + { + //keyCodes + string[] names = System.Enum.GetNames(typeof(KeyCode)); + int numberOfKeycodes = names.Length; + + for (int i = 0; i < numberOfKeycodes; i++) + { + string output = names[i]; + + if (output.Contains("Keypad")) + { + output = "[" + output.Substring(6).ToLower() + "]"; + } + else if (output.Contains("Alpha")) + { + output = output.Substring(5); + } + else //lower case key + { + output = output.ToLower(); + } + + //modifiers + if (output.Contains("control")) + { + output = output.Split('c')[0] + " ctrl"; + } + else if (output.Contains("alt")) + { + output = output.Split('a')[0] + " alt"; + } + else if (output.Contains("shift")) + { + output = output.Split('s')[0] + " shift"; + } + else if (output.Contains("command")) + { + output = output.Split('c')[0] + " cmd"; + } + + //special keys + else if (output == "backslash") + { + output = @"\"; + } + else if (output == "backquote") + { + output = "`"; + } + else if (output == "[period]") + { + output = "[.]"; + } + else if (output == "[plus]") + { + output = "[+]"; + } + else if (output == "[multiply]") + { + output = "[*]"; + } + else if (output == "[divide]") + { + output = "[/]"; + } + else if (output == "[minus]") + { + output = "[-]"; + } + else if (output == "[enter]") + { + output = "enter"; + } + else if (output.Contains("page")) + { + output = output.Insert(4, " "); + } + else if (output.Contains("arrow")) + { + output = output.Split('a')[0]; + } + else if (output == "capslock") + { + output = "caps lock"; + } + else if (output == "minus") + { + output = "-"; + } + + //test if input is valid + try + { + if (Input.GetKey(output)) + { + return output; + } + } + catch (System.Exception) + { + } + } + + //mouse + for (int m = 0; m < 6; m++) + { + string inputString = "mouse " + m; + try + { + if (Input.GetKey(inputString)) + { + return inputString; + } + } + catch (UnityException) + { + Debug.Log("Invalid mouse: " + inputString); + } + } + + //joysticks + for (int j = 1; j < 12; j++) + { + for (int b = 0; b < 20; b++) + { + string inputString = "joystick " + j + " button " + b; + try + { + if (Input.GetKey(inputString)) + { + return inputString; + } + } + catch (UnityException) + { + return string.Empty; + } + } + } + + return string.Empty; + } + + public static bool GetKey(BDInputInfo input) + { + return input.inputString != string.Empty && Input.GetKey(input.inputString); + } + + public static bool GetKeyDown(BDInputInfo input) + { + return input.inputString != string.Empty && Input.GetKeyDown(input.inputString); + } + } +} diff --git a/BDArmory/UI/BDKeyBinder.cs b/BDArmory/UI/BDKeyBinder.cs new file mode 100644 index 000000000..3f6eadf2a --- /dev/null +++ b/BDArmory/UI/BDKeyBinder.cs @@ -0,0 +1,75 @@ +using System.Collections; +using UnityEngine; + +namespace BDArmory.UI +{ + public class BDKeyBinder : MonoBehaviour + { + public static BDKeyBinder current; + public int id; + public bool valid; + string inputString = string.Empty; + bool mouseUp; + + public void StartRecording() + { + StartCoroutine(RecordKeyRoutine()); + } + + IEnumerator RecordKeyRoutine() + { + while (!valid) + { + if (mouseUp) + { + string iString = BDInputUtils.GetInputString(); + if (iString.Length > 0) + { + inputString = iString; + valid = true; + } + } + + if (Input.GetKeyUp(KeyCode.Mouse0)) + { + mouseUp = true; + } + yield return null; + } + } + + public bool AcquireInputString(out string _inputString) + { + if (valid) + { + _inputString = inputString; + current = null; + Destroy(gameObject); + return true; + } + else + { + _inputString = string.Empty; + return false; + } + } + + public static void BindKey(int id) + { + if (current != null) + { + Debug.Log("[BDArmory]: Tried to bind key but key binder is in use."); + return; + } + + current = new GameObject().AddComponent(); + current.id = id; + current.StartRecording(); + } + + public static bool IsRecordingID(int id) + { + return (current && current.id == id); + } + } +} diff --git a/BDArmory/UI/BDStagingAreaGauge.cs b/BDArmory/UI/BDStagingAreaGauge.cs new file mode 100644 index 000000000..692f47d28 --- /dev/null +++ b/BDArmory/UI/BDStagingAreaGauge.cs @@ -0,0 +1,209 @@ +using BDArmory.Core; +using KSP.UI.Screens; +using UnityEngine; +using KSP.Localization; + +namespace BDArmory.UI +{ + public class BDStagingAreaGauge : PartModule + { + public AudioSource AudioSource; + public AudioClip ReloadAudioClip = null; + public AudioClip ReloadCompleteAudioClip = null; + + public string AmmoName = ""; + + //UI gauges(next to staging icon) + private ProtoStageIconInfo heatGauge; + private ProtoStageIconInfo emptyGauge; + private ProtoStageIconInfo ammoGauge; + private ProtoStageIconInfo reloadBar; + + void Start() + { + GameEvents.onVesselSwitching.Add(ReloadIconOnVesselSwitch); + part.stagingIconAlwaysShown = true; + part.stackIconGrouping = StackIconGrouping.SAME_TYPE; + ForceRedraw(); + } + + void OnDestroy() + { + GameEvents.onVesselSwitching.Remove(ReloadIconOnVesselSwitch); + } + + private void ReloadIconOnVesselSwitch(Vessel data0, Vessel data1) + { + if (part?.vessel != null && part.vessel.isActiveVessel) + { + ForceRedraw(); + } + } + + public void UpdateAmmoMeter(float ammoLevel) + { + if (BDArmorySettings.SHOW_AMMO_GAUGES && !BDArmorySettings.INFINITE_AMMO) + { + if (ammoLevel > 0) + { + if (emptyGauge != null) + { + ForceRedraw(); + } + if (ammoGauge == null) + { + ammoGauge = InitAmmoGauge(AmmoName); + } + ammoGauge?.SetValue(ammoLevel, 0, 1); + } + else + { + if (ammoGauge != null) + { + ForceRedraw(); + } + if (emptyGauge == null) + { + emptyGauge = InitEmptyGauge(); + emptyGauge?.SetValue(1, 0, 1); + } + } + } + else if (ammoGauge != null || emptyGauge != null) + { + ForceRedraw(); + } + } + + /// 0 is no heat, 1 is max heat + public void UpdateHeatMeter(float heatLevel) + { + //heat + if (heatLevel > (1f / 3)) + { + if (heatGauge == null) + { + heatGauge = InitHeatGauge(); + } + heatGauge?.SetValue((heatLevel * 3 - 1) / 2, 0, 1); //null check + } + else if (heatGauge != null && heatLevel < 0.25f) + { + ForceRedraw(); + } + } + + /// 0 is just fired, 1 is just reloaded + public void UpdateReloadMeter(float reloadRemaining) + { + if (reloadRemaining < 1) + { + if (reloadBar == null) + { + reloadBar = InitReloadBar(); + if (ReloadAudioClip) + { + AudioSource.PlayOneShot(ReloadAudioClip); + } + } + reloadBar?.SetValue(reloadRemaining, 0, 1); + } + else if (reloadBar != null) + { + ForceRedraw(); + if (ReloadCompleteAudioClip) + { + AudioSource.PlayOneShot(ReloadCompleteAudioClip); + } + } + } + + private void ForceRedraw() + { + part.stackIcon.ClearInfoBoxes(); + //null everything so other gauges will perperly re-initialize post ClearinfoBoxes() + ammoGauge = null; + heatGauge = null; + reloadBar = null; + emptyGauge = null; + } + + private void EnsureStagingIcon() + { + // Fallback icon in case no icon is set for the part + if (string.IsNullOrEmpty(part.stagingIcon)) + { + part.stagingIcon = "SOLID_BOOSTER"; + part.stackIcon.CreateIcon(); + part.stagingIconAlwaysShown = true; + part.stackIconGrouping = StackIconGrouping.SAME_TYPE; + ForceRedraw(); + } + } + + private ProtoStageIconInfo InitReloadBar() + { + EnsureStagingIcon(); + ProtoStageIconInfo v = part.stackIcon.DisplayInfo(); + if (v == null) + return v; + v.SetMsgBgColor(XKCDColors.DarkGrey); + v.SetMsgTextColor(XKCDColors.White); + v.SetMessage(Localizer.Format("#LOC_BDArmory_ProtoStageIconInfo_Reloading"));//"Reloading" + v.SetProgressBarBgColor(XKCDColors.DarkGrey); + v.SetProgressBarColor(XKCDColors.Silver); + + return v; + } + + private ProtoStageIconInfo InitHeatGauge() //thanks DYJ + { + EnsureStagingIcon(); + ProtoStageIconInfo v = part.stackIcon.DisplayInfo(); + + // fix nullref if no stackicon exists + if (v != null) + { + v.SetMsgBgColor(XKCDColors.DarkRed); + v.SetMsgTextColor(XKCDColors.Orange); + v.SetMessage(Localizer.Format("#LOC_BDArmory_ProtoStageIconInfo_Overheat"));//"Overheat" + v.SetProgressBarBgColor(XKCDColors.DarkRed); + v.SetProgressBarColor(XKCDColors.Orange); + } + return v; + } + + private ProtoStageIconInfo InitAmmoGauge(string ammoName) //thanks DYJ + { + EnsureStagingIcon(); + ProtoStageIconInfo a = part.stackIcon.DisplayInfo(); + // fix nullref if no stackicon exists + if (a != null) + { + a.SetMsgBgColor(XKCDColors.Grey); + a.SetMsgTextColor(XKCDColors.Yellow); + //a.SetMessage("Ammunition"); + a.SetMessage($"{ammoName}"); + a.SetProgressBarBgColor(XKCDColors.DarkGrey); + a.SetProgressBarColor(XKCDColors.Yellow); + } + return a; + } + + private ProtoStageIconInfo InitEmptyGauge() //could remove emptygauge, mainly a QoL thing, removal might increase performance slightly + { + EnsureStagingIcon(); + ProtoStageIconInfo g = part.stackIcon.DisplayInfo(); + // fix nullref if no stackicon exists + if (g != null) + { + g.SetMsgBgColor(XKCDColors.AlmostBlack); + g.SetMsgTextColor(XKCDColors.Yellow); + g.SetMessage(Localizer.Format("#LOC_BDArmory_ProtoStageIconInfo_AmmoOut"));//"Ammo Depleted" + g.SetProgressBarBgColor(XKCDColors.Yellow); + g.SetProgressBarColor(XKCDColors.Black); + } + return g; + } + } +} diff --git a/BDArmory/UI/BDTeamSelector.cs b/BDArmory/UI/BDTeamSelector.cs new file mode 100644 index 000000000..53b24facb --- /dev/null +++ b/BDArmory/UI/BDTeamSelector.cs @@ -0,0 +1,164 @@ +using System.Collections; +using BDArmory.Misc; +using BDArmory.Modules; +using UnityEngine; +using KSP.Localization; + +namespace BDArmory.UI +{ + [KSPAddon(KSPAddon.Startup.FlightAndEditor, false)] + public class BDTeamSelector : MonoBehaviour + { + public static BDTeamSelector Instance; + + const float width = 250; + const float margin = 5; + const float buttonHeight = 20; + const float buttonGap = 2; + const float newTeanButtonWidth = 40; + const float scrollWidth = 20; + + private int guiCheckIndex; + private bool ready = false; + private bool open = false; + private Rect window; + private float height; + private bool scrollable; + private Vector2 scrollPosition = Vector2.zero; + + private Vector2 windowLocation; + private MissileFire targetWeaponManager; + private string newTeamName = string.Empty; + + public void Open(MissileFire weaponManager, Vector2 position) + { + open = true; + targetWeaponManager = weaponManager; + newTeamName = string.Empty; + windowLocation = position; + } + + private void TeamSelectorWindow(int id) + { + height = margin; + // Team input field + newTeamName = GUI.TextField(new Rect(margin, margin, width - buttonGap - 2 * margin - newTeanButtonWidth, buttonHeight), newTeamName, 30); + + // New team button + Rect newTeamButtonRect = new Rect(width - margin - newTeanButtonWidth, height, newTeanButtonWidth, buttonHeight); + if (GUI.Button(newTeamButtonRect, Localizer.Format("#LOC_BDArmory_Generic_New"), BDArmorySetup.BDGuiSkin.button))//"New" + { + if (!string.IsNullOrEmpty(newTeamName.Trim())) + { + targetWeaponManager.SetTeam(BDTeam.Get(newTeamName.Trim())); + open = false; + } + } + + height += buttonHeight; + + // Scrollable list of existing teams + scrollable = (BDArmorySetup.Instance.Teams.Count * (buttonHeight + buttonGap) * 2 > Screen.height); + + if (scrollable) + scrollPosition = GUI.BeginScrollView( + new Rect(margin, height, width - margin * 2 + scrollWidth, Screen.height / 2), + scrollPosition, + new Rect(margin, height, width - margin * 2, BDArmorySetup.Instance.Teams.Count * (buttonHeight + buttonGap)), + false, true); + + using (var teams = BDArmorySetup.Instance.Teams.Values.GetEnumerator()) + while (teams.MoveNext()) + { + if (teams.Current == null || !teams.Current.Name.ToLowerInvariant().StartsWith(newTeamName.ToLowerInvariant().Trim())) continue; + + height += buttonGap; + Rect buttonRect = new Rect(margin, height, width - 2 * margin, buttonHeight); + GUIStyle buttonStyle = (teams.Current == targetWeaponManager.Team) ? BDArmorySetup.BDGuiSkin.box : BDArmorySetup.BDGuiSkin.button; + + if (GUI.Button(buttonRect, teams.Current.Name, buttonStyle)) + { + targetWeaponManager.SetTeam(teams.Current); + open = false; + } + + height += buttonHeight; + } + + if (scrollable) + GUI.EndScrollView(); + + // Buttons + if (Event.current.type == EventType.KeyUp) + { + if ((Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter) && !string.IsNullOrEmpty(newTeamName.Trim())) + { + targetWeaponManager.SetTeam(BDTeam.Get(newTeamName.Trim())); + open = false; + } + else if (Event.current.keyCode == KeyCode.Escape) + { + open = false; + } + } + + height += margin; + BDGUIUtils.RepositionWindow(ref window); + BDGUIUtils.UseMouseEventInRect(window); + } + + protected virtual void OnGUI() + { + if (ready) + { + if (open && BDArmorySetup.GAME_UI_ENABLED + && Event.current.type == EventType.MouseDown + && !window.Contains(Event.current.mousePosition)) + { + open = false; + } + + if (open && BDArmorySetup.GAME_UI_ENABLED) + { + var clientRect = new Rect( + Mathf.Min(windowLocation.x, Screen.width - (scrollable ? width + scrollWidth : width)), + Mathf.Min(windowLocation.y, Screen.height - height), + width, + scrollable ? Screen.height / 2 + buttonHeight + buttonGap + 2 * margin : height); + window = GUI.Window(10591029, clientRect, TeamSelectorWindow, "", BDArmorySetup.BDGuiSkin.window); + Misc.Misc.UpdateGUIRect(window, guiCheckIndex); + } + else + { + Misc.Misc.UpdateGUIRect(new Rect(), guiCheckIndex); + } + } + } + + private void Awake() + { + if (Instance) + Destroy(Instance); + Instance = this; + } + + private void Start() + { + StartCoroutine(WaitForBdaSettings()); + } + + private void OnDestroy() + { + ready = false; + } + + private IEnumerator WaitForBdaSettings() + { + while (BDArmorySetup.Instance == null) + yield return null; + + ready = true; + guiCheckIndex = Misc.Misc.RegisterGUIRect(new Rect()); + } + } +} diff --git a/BDArmory/UI/IBDWMModule.cs b/BDArmory/UI/IBDWMModule.cs new file mode 100644 index 000000000..4c651e466 --- /dev/null +++ b/BDArmory/UI/IBDWMModule.cs @@ -0,0 +1,17 @@ +namespace BDArmory.UI +{ + /// + /// Implement this interface for your module to appear in the weapon manager modules list + /// + public interface IBDWMModule + { + // module name + string Name { get; } + + // is the module enabled + bool Enabled { get; } + + // toggle the module + void Toggle(); + } +} diff --git a/BDArmory/UI/KrakensbaneDebug.cs b/BDArmory/UI/KrakensbaneDebug.cs new file mode 100644 index 000000000..5b5fa880d --- /dev/null +++ b/BDArmory/UI/KrakensbaneDebug.cs @@ -0,0 +1,43 @@ +#if DEBUG + +// This will only be live in debug builds +using System; +using UnityEngine; +using BDArmory.Core; +using BDArmory.Misc; + +namespace BDArmory.UI +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class KrakensbaneDebug : MonoBehaviour + { + float lastShift = 0; + + void FixedUpdate() + { + if (!FloatingOrigin.Offset.IsZero()) + lastShift = Time.time; + } + + void OnGUI() + { + if (BDArmorySettings.DRAW_DEBUG_LABELS) + { + var frameVelocity = Krakensbane.GetFrameVelocityV3f(); + //var rFrameVelocity = FlightGlobals.currentMainBody.getRFrmVel(Vector3d.zero); + //var rFrameRotation = rFrameVelocity - FlightGlobals.currentMainBody.getRFrmVel(VectorUtils.GetUpDirection(Vector3.zero)); + GUI.Label(new Rect(10, 60, 400, 400), + $"Frame velocity: {frameVelocity.magnitude} ({frameVelocity}){Environment.NewLine}" + + $"Last offset {Time.time - lastShift}s ago{Environment.NewLine}" + + $"Local vessel speed: {FlightGlobals.ActiveVessel.rb_velocity.magnitude}, ({FlightGlobals.ActiveVessel.rb_velocity}){Environment.NewLine}" + //+ $"Reference frame speed: {rFrameVelocity}{Environment.NewLine}" + //+ $"Reference frame rotation speed: {rFrameRotation}{Environment.NewLine}" + //+ $"Reference frame angular speed: {rFrameRotation.magnitude / Mathf.PI * 180}{Environment.NewLine}" + //+ $"Ref frame is {(FlightGlobals.RefFrameIsRotating ? "" : "not ")}rotating{Environment.NewLine}" + ); + } + } + } +} + +#endif diff --git a/BDArmory/UI/LoadedVesselSwitcher.cs b/BDArmory/UI/LoadedVesselSwitcher.cs new file mode 100644 index 000000000..3bbc07f70 --- /dev/null +++ b/BDArmory/UI/LoadedVesselSwitcher.cs @@ -0,0 +1,327 @@ +using System.Collections; +using System.Collections.Generic; +using BDArmory.Misc; +using BDArmory.Modules; +using UnityEngine; +using KSP.Localization; + +namespace BDArmory.UI +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class LoadedVesselSwitcher : MonoBehaviour + { + private readonly float _buttonGap = 1; + private readonly float _buttonHeight = 20; + + private int _guiCheckIndex; + public LoadedVesselSwitcher Instance; + private readonly float _margin = 5; + + private bool _ready; + private bool _showGui; + private bool _teamSwitchDirty; + private readonly float _titleHeight = 30; + private float updateTimer = 0; + + //gui params + private float _windowHeight; //auto adjusting + private readonly float _windowWidth = 250; + + private SortedList> weaponManagers = new SortedList>(); + + private MissileFire _wmToSwitchTeam; + + private void Awake() + { + if (Instance) + Destroy(this); + else + Instance = this; + } + + private void Start() + { + UpdateList(); + GameEvents.onVesselCreate.Add(VesselEventUpdate); + GameEvents.onVesselDestroy.Add(VesselEventUpdate); + GameEvents.onVesselGoOffRails.Add(VesselEventUpdate); + GameEvents.onVesselGoOnRails.Add(VesselEventUpdate); + MissileFire.OnChangeTeam += MissileFireOnToggleTeam; + + _ready = false; + StartCoroutine(WaitForBdaSettings()); + + // TEST + FloatingOrigin.fetch.threshold = 20000; //20km + FloatingOrigin.fetch.thresholdSqr = 20000 * 20000; //20km + Debug.Log($"FLOATINGORIGIN: threshold is {FloatingOrigin.fetch.threshold}"); + + //BDArmorySetup.WindowRectVesselSwitcher = new Rect(10, Screen.height / 6f, _windowWidth, 10); + } + + private void OnDestroy() + { + GameEvents.onVesselCreate.Remove(VesselEventUpdate); + GameEvents.onVesselDestroy.Remove(VesselEventUpdate); + GameEvents.onVesselGoOffRails.Remove(VesselEventUpdate); + GameEvents.onVesselGoOnRails.Remove(VesselEventUpdate); + MissileFire.OnChangeTeam -= MissileFireOnToggleTeam; + + _ready = false; + + // TEST + Debug.Log($"FLOATINGORIGIN: threshold is {FloatingOrigin.fetch.threshold}"); + } + + private IEnumerator WaitForBdaSettings() + { + while (BDArmorySetup.Instance == null) + yield return null; + + _ready = true; + BDArmorySetup.Instance.hasVS = true; + _guiCheckIndex = Misc.Misc.RegisterGUIRect(new Rect()); + } + + private void MissileFireOnToggleTeam(MissileFire wm, BDTeam team) + { + if (_showGui) + UpdateList(); + } + + private void VesselEventUpdate(Vessel v) + { + if (_showGui) + UpdateList(); + } + + private void Update() + { + if (_ready) + { + if (BDArmorySetup.Instance.showVSGUI != _showGui) + { + updateTimer -= Time.fixedDeltaTime; + _showGui = BDArmorySetup.Instance.showVSGUI; + if (_showGui && updateTimer < 0) + { + UpdateList(); + updateTimer = 0.5f; //next update in half a sec only + } + } + + if (_showGui) + { + Hotkeys(); + } + } + } + + private void Hotkeys() + { + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.VS_SWITCH_NEXT)) + SwitchToNextVessel(); + if (BDInputUtils.GetKeyDown(BDInputSettingsFields.VS_SWITCH_PREV)) + SwitchToPreviousVessel(); + } + + private void UpdateList() + { + weaponManagers.Clear(); + + List.Enumerator v = FlightGlobals.Vessels.GetEnumerator(); + while (v.MoveNext()) + { + if (v.Current == null || !v.Current.loaded || v.Current.packed) + continue; + using (var wms = v.Current.FindPartModulesImplementing().GetEnumerator()) + while (wms.MoveNext()) + if (wms.Current != null) + { + if (weaponManagers.TryGetValue(wms.Current.Team.Name, out var teamManagers)) + teamManagers.Add(wms.Current); + else + weaponManagers.Add(wms.Current.Team.Name, new List { wms.Current }); + break; + } + } + v.Dispose(); + } + + private void OnGUI() + { + if (_ready) + { + if (_showGui && BDArmorySetup.GAME_UI_ENABLED) + { + SetNewHeight(_windowHeight); + // this Rect initialization ensures any save issues with height or width of the window are resolved + BDArmorySetup.WindowRectVesselSwitcher = new Rect(BDArmorySetup.WindowRectVesselSwitcher.x, BDArmorySetup.WindowRectVesselSwitcher.y, _windowWidth, _windowHeight); + BDArmorySetup.WindowRectVesselSwitcher = GUI.Window(10293444, BDArmorySetup.WindowRectVesselSwitcher, WindowVesselSwitcher, Localizer.Format("#LOC_BDArmory_BDAVesselSwitcher_Title"),//"BDA Vessel Switcher" + BDArmorySetup.BDGuiSkin.window); + Misc.Misc.UpdateGUIRect(BDArmorySetup.WindowRectVesselSwitcher, _guiCheckIndex); + } + else + { + Misc.Misc.UpdateGUIRect(new Rect(), _guiCheckIndex); + } + + if (_teamSwitchDirty) + { + if (_wmToSwitchTeam) + _wmToSwitchTeam.NextTeam(); + _teamSwitchDirty = false; + _wmToSwitchTeam = null; + } + } + } + + private void SetNewHeight(float windowHeight) + { + BDArmorySetup.WindowRectVesselSwitcher.height = windowHeight; + } + + private void WindowVesselSwitcher(int id) + { + GUI.DragWindow(new Rect(0, 0, _windowWidth - _buttonHeight - 4, _titleHeight)); + if (GUI.Button(new Rect(_windowWidth - _buttonHeight - 4, 4, _buttonHeight, _buttonHeight), "X", + BDArmorySetup.BDGuiSkin.button)) + { + BDArmorySetup.Instance.showVSGUI = false; + return; + } + float height = _titleHeight; + float vesselButtonWidth = _windowWidth - 2 * _margin - 3 * _buttonHeight; + + using (var teamManagers = weaponManagers.GetEnumerator()) + while (teamManagers.MoveNext()) + { + height += _margin; + GUI.Label(new Rect(_margin, height, _windowWidth - 2 * _margin, _buttonHeight), $"{teamManagers.Current.Key}:", BDArmorySetup.BDGuiSkin.label); + height += _buttonHeight; + + using (var wm = teamManagers.Current.Value.GetEnumerator()) + while (wm.MoveNext()) + { + if (wm.Current == null) continue; + + Rect buttonRect = new Rect(_margin, height, vesselButtonWidth, _buttonHeight); + GUIStyle vButtonStyle = wm.Current.vessel.isActiveVessel ? BDArmorySetup.BDGuiSkin.box : BDArmorySetup.BDGuiSkin.button; + string status = UpdateVesselStatus(wm.Current, vButtonStyle); + + if (GUI.Button(buttonRect, status + wm.Current.vessel.GetName(), vButtonStyle)) + ForceSwitchVessel(wm.Current.vessel); + + //guard toggle + GUIStyle guardStyle = wm.Current.guardMode ? BDArmorySetup.BDGuiSkin.box : BDArmorySetup.BDGuiSkin.button; + Rect guardButtonRect = new Rect(_margin + vesselButtonWidth, height, _buttonHeight, _buttonHeight); + if (GUI.Button(guardButtonRect, "G", guardStyle)) + wm.Current.ToggleGuardMode(); + + //AI toggle + if (wm.Current.AI != null) + { + GUIStyle aiStyle = wm.Current.AI.pilotEnabled ? BDArmorySetup.BDGuiSkin.box : BDArmorySetup.BDGuiSkin.button; + Rect aiButtonRect = new Rect(_margin + vesselButtonWidth + _buttonHeight, height, _buttonHeight, + _buttonHeight); + if (GUI.Button(aiButtonRect, "P", aiStyle)) + wm.Current.AI.TogglePilot(); + } + + //team toggle + Rect teamButtonRect = new Rect(_margin + vesselButtonWidth + _buttonHeight * 2, height, + _buttonHeight, _buttonHeight); + if (GUI.Button(teamButtonRect, "T", BDArmorySetup.BDGuiSkin.button)) + { + if (Event.current.button == 1) + { + BDTeamSelector.Instance.Open(wm.Current, new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)); + } + else + { + _wmToSwitchTeam = wm.Current; + _teamSwitchDirty = true; + } + } + + height += _buttonHeight + _buttonGap; + } + } + + height += _margin; + _windowHeight = height; + BDGUIUtils.RepositionWindow(ref BDArmorySetup.WindowRectVesselSwitcher); + } + + private string UpdateVesselStatus(MissileFire wm, GUIStyle vButtonStyle) + { + string status = ""; + if (wm.vessel.LandedOrSplashed) + { + if (wm.vessel.Landed) + status = Localizer.Format("#LOC_BDArmory_VesselStatus_Landed");//"(Landed)" + else + status = Localizer.Format("#LOC_BDArmory_VesselStatus_Splashed");//"(Splashed)" + vButtonStyle.fontStyle = FontStyle.Italic; + } + else + { + vButtonStyle.fontStyle = FontStyle.Normal; + } + return status; + } + + private void SwitchToNextVessel() + { + if (weaponManagers.Count == 0) return; + + bool switchNext = false; + + using (var teamManagers = weaponManagers.GetEnumerator()) + while (teamManagers.MoveNext()) + using (var wm = teamManagers.Current.Value.GetEnumerator()) + while (wm.MoveNext()) + { + if (wm.Current.vessel.isActiveVessel) + switchNext = true; + else if (switchNext) + { + ForceSwitchVessel(wm.Current.vessel); + return; + } + } + var firstVessel = weaponManagers.Values[0][0].vessel; + if (!firstVessel.isActiveVessel) + ForceSwitchVessel(firstVessel); + } + + private void SwitchToPreviousVessel() + { + if (weaponManagers.Count == 0) return; + + Vessel previousVessel = weaponManagers.Values[weaponManagers.Count - 1][weaponManagers.Values[weaponManagers.Count - 1].Count - 1].vessel; + + using (var teamManagers = weaponManagers.GetEnumerator()) + while (teamManagers.MoveNext()) + using (var wm = teamManagers.Current.Value.GetEnumerator()) + while (wm.MoveNext()) + { + if (wm.Current.vessel.isActiveVessel) + { + ForceSwitchVessel(previousVessel); + return; + } + previousVessel = wm.Current.vessel; + } + if (!previousVessel.isActiveVessel) + ForceSwitchVessel(previousVessel); + } + + // Extracted method, so we dont have to call these two lines everywhere + private void ForceSwitchVessel(Vessel v) + { + FlightGlobals.ForceSetActiveVessel(v); + FlightInputHandler.ResumeVesselCtrlState(v); + } + } +} diff --git a/BahaTurret/Animation/BDALookConstraintUp.cs b/BahaTurret/Animation/BDALookConstraintUp.cs deleted file mode 100644 index 5dc3edfdb..000000000 --- a/BahaTurret/Animation/BDALookConstraintUp.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class BDALookConstraintUp : PartModule - { - - [KSPField(isPersistant = false)] - public string targetName; - - [KSPField(isPersistant = false)] - public string rotatorsName; - - - - Transform target; - Transform rotator; - - - - public void Start() - { - target = part.FindModelTransform(targetName); - rotator = part.FindModelTransform(rotatorsName); - } - - public void FixedUpdate() - { - Vector3 upAxisV = rotator.up; - - rotator.LookAt(target, upAxisV); - } - - } -} - diff --git a/BahaTurret/Animation/BDAScaleByDistance.cs b/BahaTurret/Animation/BDAScaleByDistance.cs deleted file mode 100644 index b376fc7a3..000000000 --- a/BahaTurret/Animation/BDAScaleByDistance.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using UnityEngine; - - -namespace BahaTurret -{ - public class BDAScaleByDistance : PartModule - { - [KSPField(isPersistant = false)] - public string transformToScaleName; - - public Transform transformToScale; - - [KSPField(isPersistant = false)] - public string scaleFactor = "0,0,1"; - Vector3 scaleFactorV; - - [KSPField(isPersistant = false)] - public string distanceTransformName; - - public Transform distanceTransform; - - - public override void OnStart (PartModule.StartState state) - { - ParseScale(); - transformToScale = part.FindModelTransform(transformToScaleName); - distanceTransform = part.FindModelTransform(distanceTransformName); - } - - public void FixedUpdate() - { - Vector3 finalScaleFactor; - float distance = Vector3.Distance(transformToScale.position, distanceTransform.position); - float sfX = (scaleFactorV.x != 0) ? scaleFactorV.x * distance: 1; - float sfY = (scaleFactorV.y != 0) ? scaleFactorV.y * distance : 1; - float sfZ = (scaleFactorV.z != 0) ? scaleFactorV.z * distance : 1; - finalScaleFactor = new Vector3(sfX, sfY, sfZ); - - transformToScale.localScale = finalScaleFactor; - } - - - - void ParseScale() - { - string[] split = scaleFactor.Split(','); - float[] splitF = new float[split.Length]; - for(int i = 0; i> pilots = new Dictionary>(); - pilots.Add(BDArmorySettings.BDATeams.A, new List()); - pilots.Add(BDArmorySettings.BDATeams.B, new List()); - foreach(var v in BDATargetManager.LoadedVessels) - { - if(!v || !v.loaded) continue; - BDModulePilotAI pilot = null; - foreach(var p in v.FindPartModulesImplementing()) - { - pilot = p; - break; - } - - if(!pilot || !pilot.weaponManager) continue; - - pilots[BDATargetManager.BoolToTeam(pilot.weaponManager.team)].Add(pilot); - pilot.ActivatePilot(); - pilot.standbyMode = false; - if(pilot.weaponManager.guardMode) - { - pilot.weaponManager.ToggleGuardMode(); - } - } - - //clear target database so pilots don't attack yet - BDATargetManager.ClearDatabase(); - - if(pilots[BDArmorySettings.BDATeams.A].Count == 0 || pilots[BDArmorySettings.BDATeams.B].Count == 0) - { - Debug.Log("Unable to start competition mode - one or more teams is empty"); - competitionStatus = "Competition: Failed! One or more teams is empty."; - yield return new WaitForSeconds(2); - competitionStarting = false; - yield break; - } - - BDModulePilotAI aLeader = pilots[BDArmorySettings.BDATeams.A][0]; - BDModulePilotAI bLeader = pilots[BDArmorySettings.BDATeams.B][0]; - - aLeader.weaponManager.wingCommander.CommandAllFollow(); - bLeader.weaponManager.wingCommander.CommandAllFollow(); - - - //wait till the leaders are airborne - while(aLeader && bLeader && (aLeader.vessel.LandedOrSplashed || bLeader.vessel.LandedOrSplashed)) - { - yield return null; - } - - if(!aLeader || !bLeader) - { - StopCompetition(); - } - - competitionStatus = "Competition: Sending pilots to start position."; - Vector3 aDirection = Vector3.ProjectOnPlane(aLeader.vessel.CoM - bLeader.vessel.CoM, aLeader.vessel.upAxis).normalized; - Vector3 bDirection = Vector3.ProjectOnPlane(bLeader.vessel.CoM - aLeader.vessel.CoM, bLeader.vessel.upAxis).normalized; - - Vector3 center = (aLeader.vessel.CoM + bLeader.vessel.CoM) / 2f; - Vector3 aDestination = center + (aDirection * (distance+1250f)); - Vector3 bDestination = center + (bDirection * (distance+1250f)); - aDestination = VectorUtils.WorldPositionToGeoCoords(aDestination, FlightGlobals.currentMainBody); - bDestination = VectorUtils.WorldPositionToGeoCoords(bDestination, FlightGlobals.currentMainBody); - - aLeader.CommandFlyTo(aDestination); - bLeader.CommandFlyTo(bDestination); - - Vector3 centerGPS = VectorUtils.WorldPositionToGeoCoords(center, FlightGlobals.currentMainBody); - - //wait till everyone is in position - bool waiting = true; - while(waiting) - { - waiting = false; - - if(!aLeader || !bLeader) - { - StopCompetition(); - } - - if(Vector3.Distance(aLeader.transform.position, bLeader.transform.position) < distance*1.95f) - { - waiting = true; - } - else - { - foreach(var t in pilots.Keys) - { - foreach(var p in pilots[t]) - { - if(p.currentCommand == BDModulePilotAI.PilotCommands.Follow && Vector3.Distance(p.vessel.CoM, p.commandLeader.vessel.CoM) > 1000f) - { - competitionStatus = "Competition: Waiting for teams to get in position."; - waiting = true; - } - } - } - } - - yield return null; - } - - //start the match - foreach(var t in pilots.Keys) - { - foreach(var p in pilots[t]) - { - if(!p) continue; - - //enable guard mode - if(!p.weaponManager.guardMode) - { - p.weaponManager.ToggleGuardMode(); - } - - //report all vessels - if(BDATargetManager.BoolToTeam(p.weaponManager.team) == BDArmorySettings.BDATeams.B) - { - BDATargetManager.ReportVessel(p.vessel, aLeader.weaponManager); - } - else - { - BDATargetManager.ReportVessel(p.vessel, bLeader.weaponManager); - } - - //release command - p.ReleaseCommand(); - p.defaultOrbitCoords = centerGPS; - } - } - competitionStatus = "Competition starting! Good luck!"; - yield return new WaitForSeconds(2); - competitionStarting = false; - - } - } -} - diff --git a/BahaTurret/BDAEditorCategory.cs b/BahaTurret/BDAEditorCategory.cs deleted file mode 100644 index ca4ce4529..000000000 --- a/BahaTurret/BDAEditorCategory.cs +++ /dev/null @@ -1,58 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Linq; -using System.Linq.Expressions; -//using System.Core; -using System.Collections.Generic; -using UnityEngine; -using KSP.UI.Screens; - -namespace BahaTurret -{ - [KSPAddon(KSPAddon.Startup.MainMenu, true)] - public class BDAEditorCategory : MonoBehaviour - { - private static readonly List availableParts = new List(); - - void Awake() - { - GameEvents.onGUIEditorToolbarReady.Add(BDAWeaponsCategory); - - //availableParts.Clear(); - //availableParts.AddRange(PartLoader.LoadedPartsList.BDAParts()); - - } - - void BDAWeaponsCategory() - { - const string FILTER_CATEGORY = "Filter by Function"; - const string CUSTOM_CATEGORY_NAME = "BDA Weapons"; - - availableParts.Clear(); - availableParts.AddRange(PartLoader.LoadedPartsList.BDAParts()); - - Texture2D iconTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/icon", false); - - RUI.Icons.Selectable.Icon icon = new RUI.Icons.Selectable.Icon("BDArmory", iconTex, iconTex, false); - - PartCategorizer.Category filter = PartCategorizer.Instance.filters.Find(f => f.button.categoryName == FILTER_CATEGORY); - PartCategorizer.AddCustomSubcategoryFilter(filter, CUSTOM_CATEGORY_NAME, icon, p => availableParts.Contains(p)); - - KSP.UI.UIRadioButton button = filter.button.activeButton; - //button.SetFalse(button, RUIToggleButtonTyped.ClickType.FORCED); - //button.SetTrue(button, RUIToggleButtonTyped.ClickType.FORCED, false); - } - - - - } -} - diff --git a/BahaTurret/BDAGaplessParticleEmitter.cs b/BahaTurret/BDAGaplessParticleEmitter.cs deleted file mode 100644 index 8efabb70e..000000000 --- a/BahaTurret/BDAGaplessParticleEmitter.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class BDAGaplessParticleEmitter : MonoBehaviour - { - public KSPParticleEmitter pEmitter; - - private float maxDistance = 0.6f; - - public bool emit = false; - - public Part part = null; - - public Rigidbody rb; - - Vector3 internalVelocity; - Vector3 lastPos; - - bool useInternalV = false; - - Vector3 velocity - { - get - { - if(rb) - { - return rb.velocity; - } - else if(part) - { - return part.rb.velocity; - } - else - { - useInternalV = true; - return internalVelocity; - } - } - } - - void Start() - { - pEmitter = gameObject.GetComponent(); - pEmitter.emit = false; - } - - void OnEnable() - { - lastPos = transform.position; - } - - void FixedUpdate() - { - if(!part && !rb) - { - internalVelocity = (transform.position-lastPos)/Time.fixedDeltaTime; - lastPos = transform.position; - if(emit && internalVelocity.sqrMagnitude > 562500) - { - return; //dont bridge gap if floating origin shifted - } - - } - - if(emit) - { - maxDistance = Mathf.Clamp((pEmitter.minSize/3), 0.3f, 5f) + (Mathf.Clamp((BDArmorySettings.numberOfParticleEmitters-1), 0, 20)*0.07f); - - Vector3 originalLocalPosition = gameObject.transform.localPosition; - Vector3 originalPosition = gameObject.transform.position; - - Vector3 startPosition = gameObject.transform.position; - if(useInternalV) - { - startPosition -= (velocity*Time.fixedDeltaTime); - } - else - { - startPosition += (velocity * Time.fixedDeltaTime); - } - float originalGapDistance = Vector3.Distance(originalPosition, startPosition); - float intermediateSteps = originalGapDistance/maxDistance; - - pEmitter.EmitParticle(); - gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, startPosition, maxDistance); - for(int i = 1; i < intermediateSteps; i++) - { - pEmitter.EmitParticle(); - gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, startPosition, maxDistance); - } - gameObject.transform.localPosition = originalLocalPosition; - } - } - - public void EmitParticles() - { - Vector3 originalLocalPosition = gameObject.transform.localPosition; - Vector3 originalPosition = gameObject.transform.position; - Vector3 startPosition = gameObject.transform.position + (velocity * Time.fixedDeltaTime); - float originalGapDistance = Vector3.Distance(originalPosition, startPosition); - float intermediateSteps = originalGapDistance/maxDistance; - - //gameObject.transform.position = startPosition; - for(int i = 0; i < intermediateSteps; i++) - { - pEmitter.EmitParticle(); - gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, startPosition, maxDistance); - } - gameObject.transform.localPosition = originalLocalPosition; - } - } -} - diff --git a/BahaTurret/BDAParticleSelfDestruct.cs b/BahaTurret/BDAParticleSelfDestruct.cs deleted file mode 100644 index da57bef18..000000000 --- a/BahaTurret/BDAParticleSelfDestruct.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using UnityEngine; -using System.Collections; - -namespace BahaTurret -{ - public class BDAParticleSelfDestruct : MonoBehaviour - { - KSPParticleEmitter pEmitter; - BDAGaplessParticleEmitter gpe; - - void Awake() - { - pEmitter = gameObject.GetComponent(); - gpe = gameObject.GetComponent(); - } - - void Start() - { - if(pEmitter.pe.particleCount == 0) - { - Destroy(gameObject); - } - else - { - StartCoroutine(SelfDestructRoutine()); - } - } - - IEnumerator SelfDestructRoutine() - { - pEmitter.emit = false; - if(gpe) - { - gpe.emit = false; - } - yield return new WaitForSeconds(pEmitter.maxEnergy); - Destroy(gameObject); - yield break; - } - } -} - diff --git a/BahaTurret/BDAPersistantSettingsField.cs b/BahaTurret/BDAPersistantSettingsField.cs deleted file mode 100644 index 624deceb0..000000000 --- a/BahaTurret/BDAPersistantSettingsField.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Reflection; - -namespace BahaTurret -{ - [AttributeUsage(AttributeTargets.Field)] - public class BDAPersistantSettingsField : Attribute - { - public BDAPersistantSettingsField () - { - } - - public static void Save() - { - ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); - - if(!fileNode.HasNode("BDASettings")) - { - fileNode.AddNode("BDASettings"); - } - - ConfigNode settings = fileNode.GetNode("BDASettings"); - - foreach(var field in typeof(BDArmorySettings).GetFields()) - { - if(!field.IsDefined(typeof(BDAPersistantSettingsField), false)) continue; - - settings.SetValue(field.Name, field.GetValue(null).ToString(), true); - } - - fileNode.Save(BDArmorySettings.settingsConfigURL); - } - - public static void Load() - { - ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); - if(!fileNode.HasNode("BDASettings")) return; - - ConfigNode settings = fileNode.GetNode("BDASettings"); - - foreach(var field in typeof(BDArmorySettings).GetFields()) - { - if(!field.IsDefined(typeof(BDAPersistantSettingsField), false)) continue; - - if(settings.HasValue(field.Name)) - { - object parsedValue = ParseValue(field.FieldType, settings.GetValue(field.Name)); - if(parsedValue != null) - { - field.SetValue(null, parsedValue); - } - } - } - } - - public static object ParseValue(Type type, string value) - { - if(type == typeof(string)) - { - return value; - } - - if(type == typeof(bool)) - { - return bool.Parse(value); - } - else if(type.IsEnum) - { - return Enum.Parse(type, value); - } - else if(type == typeof(float)) - { - return float.Parse(value); - } - else if(type == typeof(Single)) - { - return Single.Parse(value); - } - UnityEngine.Debug.LogError("BDAPersistantSettingsField to parse settings field of type "+type.ToString()+" and value "+value); - - return null; - } - - } -} - diff --git a/BahaTurret/BDAShaderLoader.cs b/BahaTurret/BDAShaderLoader.cs deleted file mode 100644 index 266b89d47..000000000 --- a/BahaTurret/BDAShaderLoader.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections; -using System.Reflection; -using System.IO; -using UnityEngine; -using KSPAssets.Loaders; -using KSPAssets; -namespace BahaTurret -{ - [KSPAddon(KSPAddon.Startup.MainMenu, true)] - public class BDAShaderLoader : MonoBehaviour - { - private static bool loaded = false; - public static Shader GrayscaleEffectShader; - public static Shader UnlitBlackShader; - public static Shader BulletShader; - - void Start() - { - if(!loaded) - { - StartCoroutine(LoadRoutine()); - loaded = true; - } - } - - IEnumerator LoadRoutine() - { - while(!AssetLoader.Ready) - { - yield return null; - } - - - AssetDefinition bulletDef = AssetLoader.GetAssetDefinitionWithName("BDArmory/AssetBundles/bdabulletshader", "BDArmory/Bullet"); - AssetDefinition unlitBlackDef = AssetLoader.GetAssetDefinitionWithName("BDArmory/AssetBundles/bdaunlitblack", "BDArmory/Unlit Black"); - AssetDefinition grayscaleDef = AssetLoader.GetAssetDefinitionWithName("BDArmory/AssetBundles/bdagrayscaleshader", "BDArmory/Grayscale Effect"); - AssetDefinition[] assetDefs = new AssetDefinition[]{ bulletDef, unlitBlackDef, grayscaleDef }; - AssetLoader.LoadAssets(AssetLoaded, assetDefs); - } - - - void AssetLoaded(AssetLoader.Loader loader) - { - Debug.Log("BDArmory loaded shaders: "); - for(int i = 0; i < loader.objects.Length; i++) - { - Shader s = (Shader)loader.objects[i]; - if(s == null) continue; - - Debug.Log("- " + s.name); - - if(s.name == "BDArmory/Bullet") - { - BulletShader = s; - } - else if(s.name == "BDArmory/Unlit Black") - { - UnlitBlackShader = s; - } - else if(s.name == "BDArmory/Grayscale Effect") - { - GrayscaleEffectShader = s; - } - } - } - - /* - public static Shader LoadManifestShader(string manifestResource) - { - Assembly assembly = Assembly.GetExecutingAssembly(); - Stream stream = assembly.GetManifestResourceStream(manifestResource); - if(stream!=null) - { - StreamReader reader = new StreamReader(stream); - - Material mat = new Material(reader.ReadToEnd()); - return mat.shader; - } - else - { - Debug.Log ("ShaderLoader: Failed to acquire stream from manifest resource."); - } - return null; - } - */ - } - - -} - diff --git a/BahaTurret/BDATargetManager.cs b/BahaTurret/BDATargetManager.cs deleted file mode 100644 index db6e540f7..000000000 --- a/BahaTurret/BDATargetManager.cs +++ /dev/null @@ -1,958 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using KSP.UI.Screens; - - -namespace BahaTurret -{ - [KSPAddon(KSPAddon.Startup.Flight, false)] - public class BDATargetManager : MonoBehaviour - { - public static Dictionary> TargetDatabase; - - public static Dictionary> GPSTargets; - - public static List ActiveLasers; - - public static List FiredMissiles; - - public static List LoadedBuildings; - - public static List LoadedVessels; - - public static BDATargetManager Instance; - - - - string debugString = string.Empty; - - public static float heatScore = 0; - public static float flareScore = 0; - - public static bool hasAddedButton = false; - - void Awake() - { - GameEvents.onGameStateLoad.Add(LoadGPSTargets); - GameEvents.onGameStateSave.Add(SaveGPSTargets); - LoadedBuildings = new List(); - DestructibleBuilding.OnLoaded.Add(AddBuilding); - LoadedVessels = new List(); - GameEvents.onVesselLoaded.Add(AddVessel); - GameEvents.onVesselGoOnRails.Add(RemoveVessel); - GameEvents.onVesselGoOffRails.Add(AddVessel); - GameEvents.onVesselCreate.Add(AddVessel); - GameEvents.onVesselDestroy.Add(CleanVesselList); - - Instance = this; - } - - void OnDestroy() - { - if(GameEvents.onGameStateLoad != null && GameEvents.onGameStateSave != null) - { - GameEvents.onGameStateLoad.Remove(LoadGPSTargets); - GameEvents.onGameStateSave.Remove(SaveGPSTargets); - } - - GPSTargets = new Dictionary>(); - GPSTargets.Add(BDArmorySettings.BDATeams.A, new List()); - GPSTargets.Add(BDArmorySettings.BDATeams.B, new List()); - - - GameEvents.onVesselLoaded.Remove(AddVessel); - GameEvents.onVesselGoOnRails.Remove(RemoveVessel); - GameEvents.onVesselGoOffRails.Remove(AddVessel); - GameEvents.onVesselCreate.Remove(AddVessel); - GameEvents.onVesselDestroy.Remove(CleanVesselList); - } - - void Start() - { - //legacy targetDatabase - TargetDatabase = new Dictionary>(); - TargetDatabase.Add(BDArmorySettings.BDATeams.A, new List()); - TargetDatabase.Add(BDArmorySettings.BDATeams.B, new List()); - StartCoroutine(CleanDatabaseRoutine()); - - if(GPSTargets == null) - { - GPSTargets = new Dictionary>(); - GPSTargets.Add(BDArmorySettings.BDATeams.A, new List()); - GPSTargets.Add(BDArmorySettings.BDATeams.B, new List()); - } - - //Laser points - ActiveLasers = new List(); - - FiredMissiles = new List(); - - //AddToolbarButton(); - StartCoroutine(ToolbarButtonRoutine()); - - } - - - void AddBuilding(DestructibleBuilding b) - { - if(!LoadedBuildings.Contains(b)) - { - LoadedBuildings.Add(b); - } - - LoadedBuildings.RemoveAll(x => x == null); - } - - void AddVessel(Vessel v) - { - if(!LoadedVessels.Contains(v)) - { - LoadedVessels.Add(v); - } - CleanVesselList(v); - } - - void RemoveVessel(Vessel v) - { - if(v != null) - { - LoadedVessels.Remove(v); - } - CleanVesselList(v); - } - - void CleanVesselList(Vessel v) - { - LoadedVessels.RemoveAll(ves => ves == null); - LoadedVessels.RemoveAll(ves => ves.loaded == false); - } - - void AddToolbarButton() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(!hasAddedButton) - { - Texture buttonTexture = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "icon", false); - ApplicationLauncher.Instance.AddModApplication(ShowToolbarGUI, HideToolbarGUI, Dummy, Dummy, Dummy, Dummy, ApplicationLauncher.AppScenes.FLIGHT, buttonTexture); - hasAddedButton = true; - - } - } - } - - IEnumerator ToolbarButtonRoutine() - { - if(hasAddedButton) yield break; - if(!HighLogic.LoadedSceneIsFlight) yield break; - while(!ApplicationLauncher.Ready) - { - yield return null; - } - - AddToolbarButton(); - } - public void ShowToolbarGUI() - { - BDArmorySettings.toolbarGuiEnabled = true; - } - - public void HideToolbarGUI() - { - BDArmorySettings.toolbarGuiEnabled = false; - } - void Dummy() - {} - - void Update() - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - UpdateDebugLabels(); - } - - } - - - //Laser point stuff - public static void RegisterLaserPoint(ModuleTargetingCamera cam) - { - if(ActiveLasers.Contains(cam)) - { - return; - } - else - { - ActiveLasers.Add(cam); - } - } - - /// - /// Gets the laser target painter with the least angle off boresight. Set the missile as the reference transform. - /// - /// The laser target painter. - /// Reference transform. - /// Max bore sight. - public static ModuleTargetingCamera GetLaserTarget(MissileLauncher ml, bool parentOnly) - { - Transform referenceTransform = ml.transform; - float maxOffBoresight = ml.maxOffBoresight; - ModuleTargetingCamera finalCam = null; - float smallestAngle = 360; - foreach(var cam in ActiveLasers) - { - if(!cam) - { - continue; - } - - if(parentOnly && !(cam.vessel == ml.vessel || cam.vessel == ml.sourceVessel)) - { - continue; - } - - - if(cam.cameraEnabled && cam.groundStabilized && cam.surfaceDetected && !cam.gimbalLimitReached) - { - /* - if(ml.guidanceMode == MissileLauncher.GuidanceModes.BeamRiding && Vector3.Dot(ml.transform.position - cam.transform.position, ml.transform.forward) < 0) - { - continue; - } - */ - - float angle = Vector3.Angle(referenceTransform.forward, cam.groundTargetPosition-referenceTransform.position); - if(angle < maxOffBoresight && angle < smallestAngle && ml.CanSeePosition(cam.groundTargetPosition)) - { - smallestAngle = angle; - finalCam = cam; - } - } - } - return finalCam; - } - - public static TargetSignatureData GetHeatTarget(Ray ray, float scanRadius, float highpassThreshold, bool allAspect, MissileFire mf = null) - { - float minScore = highpassThreshold; - float minMass = 0.5f; - TargetSignatureData finalData = TargetSignatureData.noTarget; - float finalScore = 0; - foreach(var vessel in BDATargetManager.LoadedVessels) - { - if(!vessel || !vessel.loaded) - { - continue; - } - - TargetInfo tInfo = vessel.gameObject.GetComponent(); - if(mf == null || - !tInfo || - !(mf && tInfo.isMissile && tInfo.team != BDATargetManager.BoolToTeam(mf.team) && (tInfo.missileModule.MissileState == MissileLauncher.MissileStates.Boost || tInfo.missileModule.MissileState == MissileLauncher.MissileStates.Cruise))) - { - if(vessel.GetTotalMass() < minMass) - { - continue; - } - } - - if(RadarUtils.TerrainCheck(ray.origin, vessel.transform.position)) - { - continue; - } - - float angle = Vector3.Angle(vessel.CoM-ray.origin, ray.direction); - if(angle < scanRadius) - { - float score = 0; - foreach(var part in vessel.Parts) - { - if(!part) continue; - if(!allAspect) - { - if(!Misc.CheckSightLineExactDistance(ray.origin, part.transform.position+vessel.rb_velocity, Vector3.Distance(part.transform.position,ray.origin), 5, 5)) continue; - } - - float thisScore = (float)(part.thermalInternalFluxPrevious+part.skinTemperature) * (15/Mathf.Max(15,angle)); - thisScore *= Mathf.Pow(1400,2)/Mathf.Clamp((vessel.CoM-ray.origin).sqrMagnitude, 90000, 36000000); - score = Mathf.Max (score, thisScore); - } - - if(vessel.LandedOrSplashed) - { - score /= 4; - } - - score *= Mathf.Clamp(Vector3.Angle(vessel.transform.position-ray.origin, -VectorUtils.GetUpDirection(ray.origin))/90, 0.5f, 1.5f); - - if(score > finalScore) - { - finalScore = score; - finalData = new TargetSignatureData(vessel, score); - } - } - } - - heatScore = finalScore;//DEBUG - flareScore = 0; //DEBUG - foreach(var flare in BDArmorySettings.Flares) - { - if(!flare) continue; - - float angle = Vector3.Angle(flare.transform.position-ray.origin, ray.direction); - if(angle < scanRadius) - { - float score = flare.thermal * Mathf.Clamp01(15/angle); - score *= Mathf.Pow(1400,2)/Mathf.Clamp((flare.transform.position-ray.origin).sqrMagnitude, 90000, 36000000); - - score *= Mathf.Clamp(Vector3.Angle(flare.transform.position-ray.origin, -VectorUtils.GetUpDirection(ray.origin))/90, 0.5f, 1.5f); - - if(score > finalScore) - { - flareScore = score;//DEBUG - finalScore = score; - finalData = new TargetSignatureData(flare, score); - } - } - } - - - - if(finalScore < minScore) - { - finalData = TargetSignatureData.noTarget; - } - - return finalData; - } - - - void UpdateDebugLabels() - { - debugString = string.Empty; - debugString+= ("Team A's targets:"); - foreach(var targetInfo in TargetDatabase[BDArmorySettings.BDATeams.A]) - { - if(targetInfo) - { - if(!targetInfo.Vessel) - { - debugString+= ("\n - A target with no vessel reference."); - } - else - { - debugString+= ("\n - "+targetInfo.Vessel.vesselName+", Engaged by "+targetInfo.numFriendliesEngaging); - } - } - else - { - debugString+= ("\n - A null target info."); - } - } - debugString+= ("\nTeam B's targets:"); - foreach(var targetInfo in TargetDatabase[BDArmorySettings.BDATeams.B]) - { - if(targetInfo) - { - if(!targetInfo.Vessel) - { - debugString+= ("\n - A target with no vessel reference."); - } - else - { - debugString+= ("\n - "+targetInfo.Vessel.vesselName+", Engaged by "+targetInfo.numFriendliesEngaging); - } - } - else - { - debugString+= ("\n - A null target info."); - } - } - - debugString += "\n\nHeat score: "+heatScore; - debugString += "\nFlare score: "+flareScore; - - /* - debugString += "\n\nLoaded vessels: "; - foreach(var v in LoadedVessels) - { - if(v) - { - debugString += "\n" + v.vesselName; - } - } - */ - } - - - - - //gps stuff - void SaveGPSTargets(ConfigNode saveNode) - { - string saveTitle = HighLogic.CurrentGame.Title; - Debug.Log("Save title: " + saveTitle); - ConfigNode fileNode = ConfigNode.Load("GameData/BDArmory/gpsTargets.cfg"); - if(fileNode == null) - { - fileNode = new ConfigNode(); - fileNode.AddNode("BDARMORY"); - fileNode.Save("GameData/BDArmory/gpsTargets.cfg"); - - } - - if(fileNode!=null && fileNode.HasNode("BDARMORY")) - { - ConfigNode node = fileNode.GetNode("BDARMORY"); - - if(GPSTargets == null || !FlightGlobals.ready) - { - return; - } - - ConfigNode gpsNode = null; - if(node.HasNode("BDAGPSTargets")) - { - foreach(var n in node.GetNodes("BDAGPSTargets")) - { - if(n.GetValue("SaveGame") == saveTitle) - { - gpsNode = n; - break; - } - } - - if(gpsNode == null) - { - gpsNode = node.AddNode("BDAGPSTargets"); - gpsNode.AddValue("SaveGame", saveTitle); - } - } - else - { - gpsNode = node.AddNode("BDAGPSTargets"); - gpsNode.AddValue("SaveGame", saveTitle); - } - - if(GPSTargets[BDArmorySettings.BDATeams.A].Count == 0 && GPSTargets[BDArmorySettings.BDATeams.B].Count == 0) - { - //gpsNode.SetValue("Targets", string.Empty, true); - return; - } - - string targetString = GPSListToString(); - gpsNode.SetValue("Targets", targetString, true); - fileNode.Save("GameData/BDArmory/gpsTargets.cfg"); - Debug.Log("==== Saved BDA GPS Targets ===="); - } - } - - - - void LoadGPSTargets(ConfigNode saveNode) - { - ConfigNode fileNode = ConfigNode.Load("GameData/BDArmory/gpsTargets.cfg"); - string saveTitle = HighLogic.CurrentGame.Title; - - if(fileNode != null && fileNode.HasNode("BDARMORY")) - { - ConfigNode node = fileNode.GetNode("BDARMORY"); - - foreach(var gpsNode in node.GetNodes("BDAGPSTargets")) - { - if(gpsNode.HasValue("SaveGame") && gpsNode.GetValue("SaveGame") == saveTitle) - { - if(gpsNode.HasValue("Targets")) - { - string targetString = gpsNode.GetValue("Targets"); - if(targetString == string.Empty) - { - Debug.Log("==== BDA GPS Target string was empty! ===="); - return; - } - else - { - StringToGPSList(targetString); - Debug.Log("==== Loaded BDA GPS Targets ===="); - } - } - else - { - Debug.Log("==== No BDA GPS Targets value found! ===="); - } - } - } - } - } - - //format: SAVENAME&name,lat,long,alt;name,lat,long,alt:name,lat,long,alt (A;A;A:B;B) - private string GPSListToString() - { - string finalString = string.Empty; - string aString = string.Empty; - foreach(var gpsInfo in GPSTargets[BDArmorySettings.BDATeams.A]) - { - aString += gpsInfo.name; - aString += ","; - aString += gpsInfo.gpsCoordinates.x; - aString += ","; - aString += gpsInfo.gpsCoordinates.y; - aString += ","; - aString += gpsInfo.gpsCoordinates.z; - aString += ";"; - } - if(aString == string.Empty) - { - aString = "null"; - } - finalString += aString; - finalString += ":"; - - string bString = string.Empty; - foreach(var gpsInfo in GPSTargets[BDArmorySettings.BDATeams.B]) - { - bString += gpsInfo.name; - bString += ","; - bString += gpsInfo.gpsCoordinates.x; - bString += ","; - bString += gpsInfo.gpsCoordinates.y; - bString += ","; - bString += gpsInfo.gpsCoordinates.z; - bString += ";"; - } - if(bString == string.Empty) - { - bString = "null"; - } - finalString += bString; - - return finalString; - } - - private void StringToGPSList(string listString) - { - if(GPSTargets == null) - { - GPSTargets = new Dictionary>(); - } - GPSTargets.Clear(); - GPSTargets.Add(BDArmorySettings.BDATeams.A, new List()); - GPSTargets.Add(BDArmorySettings.BDATeams.B, new List()); - - if(listString == null || listString == string.Empty) - { - Debug.Log("=== GPS List string was empty or null ==="); - return; - } - - string[] teams = listString.Split(new char[]{ ':' }); - - Debug.Log("==== Loading GPS Targets. Number of teams: " + teams.Length); - - if(teams[0] != null && teams[0].Length > 0 && teams[0] != "null") - { - string[] teamACoords = teams[0].Split(new char[]{ ';' }); - for(int i = 0; i < teamACoords.Length; i++) - { - if(teamACoords[i] != null && teamACoords[i].Length > 0) - { - string[] data = teamACoords[i].Split(new char[]{ ',' }); - string name = data[0]; - double lat = double.Parse(data[1]); - double longi = double.Parse(data[2]); - double alt = double.Parse(data[3]); - GPSTargetInfo newInfo = new GPSTargetInfo(new Vector3d(lat, longi, alt), name); - GPSTargets[BDArmorySettings.BDATeams.A].Add(newInfo); - } - } - } - - if(teams[1] != null && teams[1].Length > 0 && teams[1] != "null") - { - string[] teamBCoords = teams[1].Split(new char[]{ ';' }); - for(int i = 0; i < teamBCoords.Length; i++) - { - if(teamBCoords[i] != null && teamBCoords[i].Length > 0) - { - string[] data = teamBCoords[i].Split(new char[]{ ',' }); - string name = data[0]; - double lat = double.Parse(data[1]); - double longi = double.Parse(data[2]); - double alt = double.Parse(data[3]); - GPSTargetInfo newInfo = new GPSTargetInfo(new Vector3d(lat, longi, alt), name); - GPSTargets[BDArmorySettings.BDATeams.B].Add(newInfo); - } - } - } - } - - - - - - - - - //Legacy target managing stuff - - public static BDArmorySettings.BDATeams BoolToTeam(bool team) - { - return team ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - } - - public static BDArmorySettings.BDATeams OtherTeam(BDArmorySettings.BDATeams team) - { - return team == BDArmorySettings.BDATeams.A ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - } - - IEnumerator CleanDatabaseRoutine() - { - while(enabled) - { - yield return new WaitForSeconds(5); - - TargetDatabase[BDArmorySettings.BDATeams.A].RemoveAll(target => target == null); - TargetDatabase[BDArmorySettings.BDATeams.A].RemoveAll(target => target.team == BDArmorySettings.BDATeams.A); - TargetDatabase[BDArmorySettings.BDATeams.A].RemoveAll(target => !target.isThreat); - - TargetDatabase[BDArmorySettings.BDATeams.B].RemoveAll(target => target == null); - TargetDatabase[BDArmorySettings.BDATeams.B].RemoveAll(target => target.team == BDArmorySettings.BDATeams.B); - TargetDatabase[BDArmorySettings.BDATeams.B].RemoveAll(target => !target.isThreat); - } - } - - void RemoveTarget(TargetInfo target, BDArmorySettings.BDATeams team) - { - TargetDatabase[team].Remove(target); - } - - public static void ReportVessel(Vessel v, MissileFire reporter) - { - if(!v) return; - if(!reporter) return; - - TargetInfo info = v.gameObject.GetComponent(); - if(!info) - { - foreach(var mf in v.FindPartModulesImplementing()) - { - if(mf.team != reporter.team) - { - info = v.gameObject.AddComponent(); - } - return; - } - - foreach(var ml in v.FindPartModulesImplementing()) - { - if(ml.hasFired) - { - if(ml.team != reporter.team) - { - info = v.gameObject.AddComponent(); - } - } - - return; - } - } - else - { - info.detectedTime = Time.time; - } - } - - public static void ClearDatabase() - { - foreach(var t in TargetDatabase.Keys) - { - foreach(var target in TargetDatabase[t]) - { - target.detectedTime = 0; - } - } - - TargetDatabase[BDArmorySettings.BDATeams.A].Clear(); - TargetDatabase[BDArmorySettings.BDATeams.B].Clear(); - } - - public static TargetInfo GetAirToAirTarget(MissileFire mf) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - TargetInfo finalTarget = null; - - float finalTargetSuitability = 0; //this will determine how suitable the target is, based on where it is located relative to the targeting vessel and how far it is - - foreach(var target in TargetDatabase[team]) - { - if(target.numFriendliesEngaging >= 2) continue; - if(target && target.Vessel && !target.isLanded && !target.isMissile) - { - Vector3 targetRelPos = target.Vessel.vesselTransform.position - mf.vessel.vesselTransform.position; - float targetSuitability = Vector3.Dot(targetRelPos.normalized, mf.vessel.ReferenceTransform.up); //prefer targets ahead to those behind - targetSuitability += 500 / (targetRelPos.magnitude + 100); - - if (finalTarget == null || (target.numFriendliesEngaging < finalTarget.numFriendliesEngaging) || targetSuitability > finalTargetSuitability + finalTarget.numFriendliesEngaging) - { - finalTarget = target; - finalTargetSuitability = targetSuitability; - } - } - } - - return finalTarget; - } - - //this will search for an AA target that is immediately in front of the AI during an extend when it would otherwise be helpless - public static TargetInfo GetAirToAirTargetAbortExtend(MissileFire mf, float maxDistance, float cosAngleCheck) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - TargetInfo finalTarget = null; - - float finalTargetSuitability = 0; //this will determine how suitable the target is, based on where it is located relative to the targeting vessel and how far it is - - foreach (var target in TargetDatabase[team]) - { - if (target && target.Vessel && !target.isLanded && !target.isMissile) - { - Vector3 targetRelPos = target.Vessel.vesselTransform.position - mf.vessel.vesselTransform.position; - - float distance, dot; - distance = targetRelPos.magnitude; - dot = Vector3.Dot(targetRelPos.normalized, mf.vessel.ReferenceTransform.up); - - if (distance > maxDistance || cosAngleCheck > dot) - continue; - - float targetSuitability = dot; //prefer targets ahead to those behind - targetSuitability += 500 / (distance + 100); //same suitability check as above - - if (finalTarget == null || targetSuitability > finalTargetSuitability) //just pick the most suitable one - { - finalTarget = target; - finalTargetSuitability = targetSuitability; - } - } - } - - return finalTarget; - } - - //returns the nearest friendly target - public static TargetInfo GetClosestFriendly(MissileFire mf) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.A : BDArmorySettings.BDATeams.B; - TargetInfo finalTarget = null; - - foreach (var target in TargetDatabase[team]) - { - if (target && target.Vessel && target.weaponManager != mf) - { - if (finalTarget == null || (target.IsCloser(finalTarget, mf))) - { - finalTarget = target; - } - } - } - - return finalTarget; - } - - //returns the target that owns this weapon manager - public static TargetInfo GetTargetFromWeaponManager(MissileFire mf) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.A : BDArmorySettings.BDATeams.B; - - foreach (var target in TargetDatabase[team]) - { - if (target && target.Vessel && target.weaponManager == mf) - { - return target; - } - } - - return null; - } - - public static TargetInfo GetClosestTarget(MissileFire mf) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - TargetInfo finalTarget = null; - - foreach(var target in TargetDatabase[team]) - { - if(target && target.Vessel && mf.CanSeeTarget(target.Vessel) && !target.isMissile) - { - if(finalTarget == null || (target.IsCloser(finalTarget, mf))) - { - finalTarget = target; - } - } - } - - return finalTarget; - } - - public static List GetAllTargetsExcluding(List excluding, MissileFire mf) - { - List finalTargets = new List(); - BDArmorySettings.BDATeams team = BoolToTeam(mf.team); - - foreach(var target in TargetDatabase[team]) - { - if(target && target.Vessel && mf.CanSeeTarget(target.Vessel) && !excluding.Contains(target)) - { - finalTargets.Add(target); - } - } - - return finalTargets; - } - - public static TargetInfo GetLeastEngagedTarget(MissileFire mf) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - TargetInfo finalTarget = null; - - foreach(var target in TargetDatabase[team]) - { - if(target && target.Vessel && mf.CanSeeTarget(target.Vessel) && !target.isMissile) - { - if(finalTarget == null || target.numFriendliesEngaging < finalTarget.numFriendliesEngaging) - { - finalTarget = target; - } - } - } - - return finalTarget; - } - - public static TargetInfo GetMissileTarget(MissileFire mf, bool targetingMeOnly = false) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - TargetInfo finalTarget = null; - - foreach(var target in TargetDatabase[team]) - { - if(target && target.Vessel && target.isMissile && target.isThreat && mf.CanSeeTarget(target.Vessel) ) - { - if(target.missileModule) - { - if(targetingMeOnly) - { - if(Vector3.SqrMagnitude(target.missileModule.targetPosition - mf.vessel.CoM) > 60 * 60) - { - continue; - } - } - } - else - { - Debug.LogWarning("checking target missile - doesn't have missile module"); - } - - - if(((finalTarget == null && target.numFriendliesEngaging < 2) || target.numFriendliesEngaging < finalTarget.numFriendliesEngaging)) - { - finalTarget = target; - } - } - } - - return finalTarget; - } - - public static TargetInfo GetUnengagedMissileTarget(MissileFire mf) - { - BDArmorySettings.BDATeams team = mf.team ? BDArmorySettings.BDATeams.B : BDArmorySettings.BDATeams.A; - - foreach(var target in TargetDatabase[team]) - { - if(target && target.Vessel && mf.CanSeeTarget(target.Vessel) && target.isMissile && target.isThreat) - { - if(target.numFriendliesEngaging == 0) - { - return target; - } - } - } - - return null; - } - - public static TargetInfo GetClosestMissileTarget(MissileFire mf) - { - BDArmorySettings.BDATeams team = BoolToTeam(mf.team); - TargetInfo finalTarget = null; - - foreach(var target in TargetDatabase[team]) - { - if(target && target.Vessel && mf.CanSeeTarget(target.Vessel) && target.isMissile) - { - bool isHostile = false; - if(target.isThreat) - { - isHostile = true; - } - - if(isHostile && (finalTarget == null || target.IsCloser(finalTarget, mf))) - { - finalTarget = target; - } - } - } - - return finalTarget; - } - - //checks to see if a friendly is too close to the gun trajectory to fire them - public static bool CheckSafeToFireGuns(MissileFire weaponManager, Vector3 aimDirection, float safeDistance, float cosUnsafeAngle) - { - BDArmorySettings.BDATeams team = weaponManager.team ? BDArmorySettings.BDATeams.A : BDArmorySettings.BDATeams.B; - foreach (var friendlyTarget in TargetDatabase[team]) - { - if (friendlyTarget && friendlyTarget.Vessel) - { - float friendlyPosDot = Vector3.Dot(friendlyTarget.position - weaponManager.vessel.vesselTransform.position, aimDirection); - if (friendlyPosDot > 0) //only bother if the friendly is actually in front of us - { - float friendlyDistance = (friendlyTarget.position - weaponManager.vessel.vesselTransform.position).magnitude; - float friendlyPosDotNorm = friendlyPosDot / friendlyDistance; //scale down the dot to be a 0-1 so we can check it againts cosUnsafeAngle - - if (friendlyDistance < safeDistance && cosUnsafeAngle < friendlyPosDotNorm) //if it's too close and it's within the Unsafe Angle, don't fire - return false; - } - } - } - - return true; - } - - - void OnGUI() - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(600,100,600,600), debugString); - } - - - } - - - - } -} - diff --git a/BahaTurret/BDATooltips.cs b/BahaTurret/BDATooltips.cs deleted file mode 100644 index cf561b987..000000000 --- a/BahaTurret/BDATooltips.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace BahaTurret -{ - public static class BDATooltips - { - public static string WM_RIPPLE - { - get - { - return "The ripple function allows you to fire missiles, rockets, or bombs at the configured rate by holding down the main fire key (" + BDInputSettingsFields.WEAP_FIRE_KEY.inputString + ")"; - } - } - - - } -} - diff --git a/BahaTurret/BDAdjustableRail.cs b/BahaTurret/BDAdjustableRail.cs deleted file mode 100644 index a608cffbb..000000000 --- a/BahaTurret/BDAdjustableRail.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class BDAdjustableRail : PartModule - { - - [KSPField(isPersistant = true)] - public float railHeight = 0; - - - [KSPField(isPersistant = true)] - public float railLength = 1; - - - Transform railLengthTransform; - Transform railHeightTransform; - - [KSPField] - public string stackNodePosition; - - Dictionary originalStackNodePosition; - - public override void OnStart (PartModule.StartState state) - { - railLengthTransform = part.FindModelTransform("Rail"); - railHeightTransform = part.FindModelTransform("RailSleeve"); - - railLengthTransform.localScale = new Vector3(1, railLength, 1); - railHeightTransform.localPosition = new Vector3(0,railHeight,0); - - if(HighLogic.LoadedSceneIsEditor) - { - ParseStackNodePosition(); - StartCoroutine(DelayedUpdateStackNode()); - } - } - - void ParseStackNodePosition() - { - originalStackNodePosition = new Dictionary(); - string[] nodes = stackNodePosition.Split(new char[]{ ';' }); - for(int i = 0; i < nodes.Length; i++) - { - string[] split = nodes[i].Split(new char[]{ ',' }); - string id = split[0]; - Vector3 position = new Vector3(float.Parse(split[1]), float.Parse(split[2]), float.Parse(split[3])); - originalStackNodePosition.Add(id, position); - } - } - - - IEnumerator DelayedUpdateStackNode() - { - yield return null; - UpdateStackNode(false); - } - - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Height ++", active = true)] - public void IncreaseHeight() - { - /* - UpdateStackNode(false); - foreach(Part sym in part.symmetryCounterparts) - { - sym.FindModuleImplementing().UpdateStackNode(false); - } - */ - railHeight = Mathf.Clamp(railHeight-0.02f, -.16f, 0); - railHeightTransform.localPosition = new Vector3(0,railHeight,0); - - UpdateStackNode(true); - - foreach(Part sym in part.symmetryCounterparts) - { - sym.FindModuleImplementing().UpdateHeight(railHeight); - } - - - } - - - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Height --", active = true)] - public void DecreaseHeight() - { - /* - UpdateStackNode(false); - foreach(Part sym in part.symmetryCounterparts) - { - sym.FindModuleImplementing().UpdateStackNode(false); - } - */ - railHeight = Mathf.Clamp(railHeight+0.02f, -.16f, 0); - railHeightTransform.localPosition = new Vector3(0,railHeight,0); - - UpdateStackNode(true); - - foreach(Part sym in part.symmetryCounterparts) - { - sym.FindModuleImplementing().UpdateHeight(railHeight); - } - } - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Length ++", active = true)] - public void IncreaseLength() - { - railLength = Mathf.Clamp(railLength+0.2f, 0.4f, 2f); - railLengthTransform.localScale = new Vector3(1, railLength, 1); - foreach(Part sym in part.symmetryCounterparts) - { - sym.FindModuleImplementing().UpdateLength(railLength); - } - } - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Length --", active = true)] - public void DecreaseLength() - { - railLength = Mathf.Clamp(railLength-0.2f, 0.4f, 2f); - railLengthTransform.localScale = new Vector3(1, railLength, 1); - foreach(Part sym in part.symmetryCounterparts) - { - sym.FindModuleImplementing().UpdateLength(railLength); - } - } - - public void UpdateHeight(float height) - { - railHeight = height; - railHeightTransform.localPosition = new Vector3(0,railHeight,0); - - UpdateStackNode(true); - } - - public void UpdateLength(float length) - { - railLength = length; - railLengthTransform.localScale = new Vector3(1, railLength, 1); - } - - public void UpdateStackNode(bool updateChild) - { - Vector3 delta = Vector3.zero; - foreach(var stackNode in part.attachNodes) - { - if(stackNode.nodeType == AttachNode.NodeType.Stack && originalStackNodePosition.ContainsKey(stackNode.id)) - { - Vector3 prevPos = stackNode.position; - - stackNode.position.y = originalStackNodePosition[stackNode.id].y + railHeight; - delta = stackNode.position - prevPos; - - } - } - - if(updateChild) - { - Vector3 worldDelta = part.transform.TransformVector(delta); - foreach(var p in part.children) - { - p.transform.position += worldDelta; - } - } - } - } -} - diff --git a/BahaTurret/BDAirspeedControl.cs b/BahaTurret/BDAirspeedControl.cs deleted file mode 100644 index feb1cd920..000000000 --- a/BahaTurret/BDAirspeedControl.cs +++ /dev/null @@ -1,202 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using System.Reflection; - -namespace BahaTurret -{ - public class BDAirspeedControl : MonoBehaviour //: PartModule - { - //[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = false, guiName = "TargetSpeed"), - // UI_FloatRange(minValue = 1f, maxValue = 420f, stepIncrement = 1f, scene = UI_Scene.All)] - public float targetSpeed = 0; - - public bool useBrakes = true; - public bool allowAfterburner = true; - - //[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = false, guiName = "ThrottleFactor"), - // UI_FloatRange(minValue = 1f, maxValue = 20f, stepIncrement = .5f, scene = UI_Scene.All)] - public float throttleFactor = 2f; - - public Vessel vessel; - - - - bool controlEnabled = false; - - //[KSPField(guiActive = true, guiName = "Thrust")] - public float debugThrust; - - List multiModeEngines; - - //[KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "ToggleAC")] - public void Toggle() - { - if(controlEnabled) - { - Deactivate(); - } - else - { - Activate(); - } - } - - public void Activate() - { - controlEnabled = true; - vessel.OnFlyByWire -= AirspeedControl; - vessel.OnFlyByWire += AirspeedControl; - multiModeEngines = new List(); - - - } - - public void Deactivate() - { - controlEnabled = false; - vessel.OnFlyByWire -= AirspeedControl; - } - - void AirspeedControl(FlightCtrlState s) - { - if(targetSpeed == 0) - { - vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); - s.mainThrottle = 0; - return; - } - - - float currentSpeed = (float) vessel.srfSpeed; - float speedError = targetSpeed - currentSpeed; - - float setAccel = speedError * throttleFactor; - - SetAcceleration(setAccel, s); - } - - - void SetAcceleration(float accel, FlightCtrlState s) - { - float gravAccel = GravAccel(); - float requestEngineAccel = accel - gravAccel; - - possibleAccel = gravAccel; - - float dragAccel = 0; - float engineAccel = MaxEngineAccel(requestEngineAccel, out dragAccel); - - if(engineAccel == 0) - { - s.mainThrottle = 0; - return; - } - - requestEngineAccel = Mathf.Clamp(requestEngineAccel, -engineAccel, engineAccel); - - float requestThrottle = (requestEngineAccel - dragAccel) / engineAccel; - - s.mainThrottle = Mathf.Clamp01(requestThrottle); - - //use brakes if overspeeding too much - if(requestThrottle < -0.5f) - { - vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); - } - else - { - vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, false); - } - } - - float MaxEngineAccel(float requestAccel, out float dragAccel) - { - float maxThrust = 0; - float finalThrust = 0; - multiModeEngines.Clear(); - - foreach(var engine in vessel.FindPartModulesImplementing()) - { - if(!engine.EngineIgnited) - { - continue; - } - - MultiModeEngine mme = engine.part.FindModuleImplementing(); - if(mme) - { - multiModeEngines.Add(mme); - mme.autoSwitch = false; - } - if(!mme || mme.mode == engine.engineID) - { - float engineThrust = engine.maxThrust; - if(engine.atmChangeFlow) - { - engineThrust *= engine.flowMultiplier; - } - maxThrust += engineThrust * (engine.thrustPercentage/100f); - - finalThrust += engine.finalThrust; - } - } - - debugThrust = maxThrust; - - float vesselMass = vessel.GetTotalMass(); - - float accel = maxThrust / vesselMass; - - - //estimate drag - float estimatedCurrentAccel = finalThrust/vesselMass; - float actualCurrentAccel = Vector3.Project(vessel.acceleration, vessel.ReferenceTransform.up).magnitude*Mathf.Sign(Vector3.Dot(vessel.acceleration, -vessel.ReferenceTransform.up)); - float accelError = (actualCurrentAccel - estimatedCurrentAccel)/2; - dragAccel = accelError; - - possibleAccel += accel; - - //use multimode afterburner for extra accel if lacking - foreach(var mme in multiModeEngines) - { - if(allowAfterburner && (accel < requestAccel * 0.2f || targetSpeed > 300)) - { - if(mme.runningPrimary) - { - mme.Events["ModeEvent"].Invoke(); - } - } - else if(!allowAfterburner || accel > requestAccel * 1.5f) - { - if(!mme.runningPrimary) - { - mme.Events["ModeEvent"].Invoke(); - } - } - } - - - - return accel; - } - - float GravAccel() - { - Vector3 geeVector = FlightGlobals.getGeeForceAtPosition(vessel.CoM); - float gravAccel = Vector3.Project(geeVector, vessel.ReferenceTransform.up).magnitude; - gravAccel *= Mathf.Sign(Vector3.Dot(vessel.ReferenceTransform.up, geeVector)); - - return gravAccel; - } - - - float possibleAccel = 0; - public float GetPossibleAccel() - { - return possibleAccel; - } - } -} - diff --git a/BahaTurret/BDArmorySettings.cs b/BahaTurret/BDArmorySettings.cs deleted file mode 100644 index 16cf86771..000000000 --- a/BahaTurret/BDArmorySettings.cs +++ /dev/null @@ -1,1650 +0,0 @@ -using System; -using UnityEngine; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; - -namespace BahaTurret -{ - [KSPAddon(KSPAddon.Startup.EveryScene, false)] - public class BDArmorySettings : MonoBehaviour - { - public static string settingsConfigURL = "GameData/BDArmory/settings.cfg"; - - - //=======configurable settings - [BDAPersistantSettingsField] - public static bool INSTAKILL = false; - [BDAPersistantSettingsField] - public static bool BULLET_HITS = true; - [BDAPersistantSettingsField] - public static float PHYSICS_RANGE = 0; - [BDAPersistantSettingsField] - public static bool EJECT_SHELLS = true; - [BDAPersistantSettingsField] - public static bool SHELL_COLLISIONS = true; - [BDAPersistantSettingsField] - public static bool INFINITE_AMMO = false; - [BDAPersistantSettingsField] - public static bool DRAW_DEBUG_LINES = false; - [BDAPersistantSettingsField] - public static bool DRAW_DEBUG_LABELS = false; - [BDAPersistantSettingsField] - public static bool DRAW_AIMERS = true; - [BDAPersistantSettingsField] - public static bool AIM_ASSIST = true; - [BDAPersistantSettingsField] - public static bool REMOTE_SHOOTING = false; - [BDAPersistantSettingsField] - public static bool BOMB_CLEARANCE_CHECK = true; - [BDAPersistantSettingsField] - public static float DMG_MULTIPLIER = 100; - [BDAPersistantSettingsField] - public static float FLARE_CHANCE_FACTOR = 25; - - public static bool SMART_GUARDS = true; - - [BDAPersistantSettingsField] - public static float MAX_BULLET_RANGE = 8000; - - [BDAPersistantSettingsField] - public static float TRIGGER_HOLD_TIME = 0.3f; - - [BDAPersistantSettingsField] - public static bool ALLOW_LEGACY_TARGETING = true; - - [BDAPersistantSettingsField] - public static float TARGET_CAM_RESOLUTION = 1024; - [BDAPersistantSettingsField] - public static bool BW_TARGET_CAM = true; - [BDAPersistantSettingsField] - public static float SMOKE_DEFLECTION_FACTOR = 10; - [BDAPersistantSettingsField] - public static float FLARE_THERMAL = 1900; - [BDAPersistantSettingsField] - public static float BDARMORY_UI_VOLUME = 0.35f; - [BDAPersistantSettingsField] - public static float BDARMORY_WEAPONS_VOLUME = 0.32f; - [BDAPersistantSettingsField] - public static float MAX_GUARD_VISUAL_RANGE = 5000; - - [BDAPersistantSettingsField] - public static float GLOBAL_LIFT_MULTIPLIER = 0.20f; - [BDAPersistantSettingsField] - public static float GLOBAL_DRAG_MULTIPLIER = 4f; - [BDAPersistantSettingsField] - public static float IVA_LOWPASS_FREQ = 2500; - [BDAPersistantSettingsField] - public static bool PEACE_MODE = false; - - //================== - //reflection field lists - FieldInfo[] iFs = null; - FieldInfo[] inputFields - { - get - { - if(iFs == null) - { - iFs = typeof(BDInputSettingsFields).GetFields(); - } - return iFs; - } - } - - //EVENTS - public delegate void VolumeChange(); - public static event VolumeChange OnVolumeChange; - - public delegate void SavedSettings(); - public static event SavedSettings OnSavedSettings; - - public delegate void PeaceEnabled(); - public static event PeaceEnabled OnPeaceEnabled; - - //particle optimization - public static int numberOfParticleEmitters = 0; - - - public static BDArmorySettings Instance; - - public static bool GAME_UI_ENABLED = true; - - //settings gui - public bool settingsGuiEnabled = false; - public string physicsRangeGui; - public string fireKeyGui; - - - //editor alignment - public static bool showWeaponAlignment = false; - - //toolbar gui - public static bool hasAddedButton = false; - public static bool toolbarGuiEnabled = false; - float toolWindowWidth = 300; - float toolWindowHeight = 100; - public Rect toolbarWindowRect; - bool showWeaponList = false; - bool showGuardMenu = false; - bool showModules = false; - int numberOfModules = 0; - - //gps window - public bool showingGPSWindow - { - get - { - return showGPSWindow; - } - } - bool showGPSWindow = false; - Rect gpsWindowRect; - float gpsEntryCount = 0; - float gpsEntryHeight = 24; - float gpsBorder = 5; - bool editingGPSName = false; - int editingGPSNameIndex = 0; - bool hasEnteredGPSName = false; - string newGPSName = string.Empty; - - public MissileFire ActiveWeaponManager = null; - public bool missileWarning = false; - public float missileWarningTime = 0; - - - - //load range stuff - VesselRanges combatVesselRanges = new VesselRanges(); - float physRangeTimer; - - - - public static List Flares = new List(); - - - //gui styles - GUIStyle centerLabel; - GUIStyle centerLabelRed; - GUIStyle centerLabelOrange; - GUIStyle centerLabelBlue; - GUIStyle leftLabel; - GUIStyle leftLabelRed; - GUIStyle rightLabelRed; - GUIStyle leftLabelGray; - GUIStyle rippleSliderStyle; - GUIStyle rippleThumbStyle; - GUIStyle kspTitleLabel; - - GUIStyle middleLeftLabel; - GUIStyle middleLeftLabelOrange; - GUIStyle targetModeStyle; - GUIStyle targetModeStyleSelected; - - public enum BDATeams{A, B, None}; - - //competition mode - float competitionDist = 8000; - string compDistGui = "8000"; - - - //common textures - public static string textureDir = "BDArmory/Textures/"; - - bool drawCursor = false; - Texture2D cursorTexture = GameDatabase.Instance.GetTexture(textureDir + "aimer", false); - - private Texture2D dti; - public Texture2D directionTriangleIcon - { - get - { - return dti ? dti : dti = GameDatabase.Instance.GetTexture(textureDir + "directionIcon", false); - } - } - - private Texture2D cgs; - public Texture2D crossedGreenSquare - { - get - { - return cgs ? cgs : cgs = GameDatabase.Instance.GetTexture(textureDir + "crossedGreenSquare", false); - } - } - - private Texture2D dlgs; - public Texture2D dottedLargeGreenCircle - { - get - { - return dlgs ? dlgs : dlgs = GameDatabase.Instance.GetTexture (textureDir + "dottedLargeGreenCircle", false); - } - } - - private Texture2D ogs; - public Texture2D openGreenSquare - { - get - { - return ogs ? ogs : ogs = GameDatabase.Instance.GetTexture(textureDir + "openGreenSquare", false); - } - } - - private Texture2D gdott; - public Texture2D greenDotTexture - { - get - { - return gdott ? gdott : gdott = GameDatabase.Instance.GetTexture(textureDir + "greenDot", false); - } - } - - private Texture2D gdt; - public Texture2D greenDiamondTexture - { - get - { - return gdt ? gdt : gdt = GameDatabase.Instance.GetTexture(textureDir + "greenDiamond", false); - } - } - - private Texture2D lgct; - public Texture2D largeGreenCircleTexture - { - get - { - return lgct ? lgct : lgct = GameDatabase.Instance.GetTexture(textureDir + "greenCircle3", false); - } - } - - private Texture2D gct; - public Texture2D greenCircleTexture - { - get - { - return gct ? gct : gct = GameDatabase.Instance.GetTexture(textureDir + "greenCircle2", false); - } - } - - private Texture2D gpct; - public Texture2D greenPointCircleTexture - { - get - { - if(gpct == null) - { - gpct = GameDatabase.Instance.GetTexture(textureDir + "greenPointCircle", false); - } - return gpct; - } - } - - private Texture2D gspct; - public Texture2D greenSpikedPointCircleTexture - { - get - { - return gspct ? gspct : gspct = GameDatabase.Instance.GetTexture(textureDir + "greenSpikedCircle", false); - } - } - - private Texture2D wSqr; - public Texture2D whiteSquareTexture - { - get - { - return wSqr ? wSqr : wSqr = GameDatabase.Instance.GetTexture(textureDir + "whiteSquare", false); - } - } - - private Texture2D oWSqr; - public Texture2D openWhiteSquareTexture - { - get - { - return oWSqr ? oWSqr : oWSqr = GameDatabase.Instance.GetTexture(textureDir + "openWhiteSquare", false);; - } - } - - private Texture2D tDir; - public Texture2D targetDirectionTexture - { - get - { - return tDir ? tDir : tDir = GameDatabase.Instance.GetTexture(textureDir + "targetDirectionIndicator", false); - } - } - - private Texture2D hInd; - public Texture2D horizonIndicatorTexture - { - get - { - return hInd ? hInd : hInd = GameDatabase.Instance.GetTexture(textureDir + "horizonIndicator", false); - } - } - - private Texture2D si; - public Texture2D settingsIconTexture - { - get - { - return si ? si : si = GameDatabase.Instance.GetTexture(textureDir + "settingsIcon", false); - } - } - //end textures - - - public static bool GameIsPaused - { - get - { - return PauseMenu.isOpen || Time.timeScale == 0; - } - } - - - - void Start() - { - Instance = this; - - //settings - SetupSettingsSize(); - LoadConfig(); - - //wmgr tolbar - toolbarWindowRect = new Rect(Screen.width-toolWindowWidth-4, 150, toolWindowWidth, toolWindowHeight); - - physRangeTimer = Time.time; - - - GAME_UI_ENABLED = true; - - - fireKeyGui = BDInputSettingsFields.WEAP_FIRE_KEY.inputString; - - //setup gui styles - centerLabel = new GUIStyle(); - centerLabel.alignment = TextAnchor.UpperCenter; - centerLabel.normal.textColor = Color.white; - - centerLabelRed = new GUIStyle(); - centerLabelRed.alignment = TextAnchor.UpperCenter; - centerLabelRed.normal.textColor = Color.red; - - centerLabelOrange = new GUIStyle(); - centerLabelOrange.alignment = TextAnchor.UpperCenter; - centerLabelOrange.normal.textColor = XKCDColors.BloodOrange; - - centerLabelBlue = new GUIStyle(); - centerLabelBlue.alignment = TextAnchor.UpperCenter; - centerLabelBlue.normal.textColor = XKCDColors.AquaBlue; - - leftLabel = new GUIStyle(); - leftLabel.alignment = TextAnchor.UpperLeft; - leftLabel.normal.textColor = Color.white; - - middleLeftLabel = new GUIStyle(leftLabel); - middleLeftLabel.alignment = TextAnchor.MiddleLeft; - - middleLeftLabelOrange = new GUIStyle(middleLeftLabel); - middleLeftLabelOrange.normal.textColor = XKCDColors.BloodOrange; - - targetModeStyle = new GUIStyle(); - targetModeStyle.alignment = TextAnchor.MiddleRight; - targetModeStyle.fontSize = 9; - targetModeStyle.normal.textColor = Color.white; - - targetModeStyleSelected = new GUIStyle(targetModeStyle); - targetModeStyleSelected.normal.textColor = XKCDColors.BloodOrange; - - leftLabelRed = new GUIStyle(); - leftLabelRed.alignment = TextAnchor.UpperLeft; - leftLabelRed.normal.textColor = Color.red; - - rightLabelRed = new GUIStyle(); - rightLabelRed.alignment = TextAnchor.UpperRight; - rightLabelRed.normal.textColor = Color.red; - - leftLabelGray = new GUIStyle(); - leftLabelGray.alignment = TextAnchor.UpperLeft; - leftLabelGray.normal.textColor = Color.gray; - - rippleSliderStyle = new GUIStyle(HighLogic.Skin.horizontalSlider); - rippleThumbStyle = new GUIStyle(HighLogic.Skin.horizontalSliderThumb); - rippleSliderStyle.fixedHeight = rippleThumbStyle.fixedHeight = 0; - - kspTitleLabel = new GUIStyle(); - kspTitleLabel.normal.textColor = HighLogic.Skin.window.normal.textColor; - kspTitleLabel.font = HighLogic.Skin.window.font; - kspTitleLabel.fontSize = HighLogic.Skin.window.fontSize; - kspTitleLabel.fontStyle = HighLogic.Skin.window.fontStyle; - kspTitleLabel.alignment = TextAnchor.UpperCenter; - // - - if(HighLogic.LoadedSceneIsFlight) - { - ApplyPhysRange(); - SaveVolumeSettings(); - - GameEvents.onHideUI.Add(HideGameUI); - GameEvents.onShowUI.Add(ShowGameUI); - GameEvents.onVesselGoOffRails.Add(OnVesselGoOffRails); - GameEvents.OnGameSettingsApplied.Add(SaveVolumeSettings); - GameEvents.onVesselCreate.Add(ApplyNewVesselRanges); - - - /* - foreach(var cam in FlightCamera.fetch.cameras) - { - cam.gameObject.AddComponent(); - } - */ - - gpsWindowRect = new Rect(0, 0, toolbarWindowRect.width-10, 0); - - GameEvents.onVesselChange.Add(VesselChange); - } - } - - - - void Update() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(missileWarning && Time.time - missileWarningTime > 1.5f) - { - missileWarning = false; - } - - /* - if(Input.GetKeyDown(KeyCode.Keypad1)) - { - VesselRanges vr = FlightGlobals.ActiveVessel.vesselRanges; - Debug.Log ("Flying: "); - Debug.Log ("load: " + vr.flying.load); - Debug.Log ("unload: " + vr.flying.unload); - Debug.Log ("pack: " + vr.flying.pack); - Debug.Log ("unpack" + vr.flying.unpack); - - Debug.Log ("Landed: "); - Debug.Log ("load: " + vr.landed.load); - Debug.Log ("unload: " + vr.landed.unload); - Debug.Log ("pack: " + vr.landed.pack); - Debug.Log ("unpack" + vr.landed.unpack); - - Debug.Log ("Splashed: "); - Debug.Log ("load: " + vr.splashed.load); - Debug.Log ("unload: " + vr.splashed.unload); - Debug.Log ("pack: " + vr.splashed.pack); - Debug.Log ("unpack" + vr.splashed.unpack); - - } - */ - - - - - - - - if(Input.GetKeyDown(KeyCode.KeypadMultiply)) - { - toolbarGuiEnabled = !toolbarGuiEnabled; - } - - } - else if(HighLogic.LoadedSceneIsEditor) - { - if(Input.GetKeyDown(KeyCode.F2)) - { - showWeaponAlignment = !showWeaponAlignment; - } - } - - if(Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) - { - if(Input.GetKeyDown(KeyCode.B)) - { - ToggleSettingsGUI(); - } - } - - } - - void ToggleSettingsGUI() - { - if(HighLogic.LoadedScene == GameScenes.LOADING || HighLogic.LoadedScene == GameScenes.LOADINGBUFFER) - { - return; - } - - settingsGuiEnabled = !settingsGuiEnabled; - if(settingsGuiEnabled) - { - physicsRangeGui = PHYSICS_RANGE.ToString(); - LoadConfig(); - } - else - { - SaveConfig(); - } - - } - - void LateUpdate() - { - if(HighLogic.LoadedSceneIsFlight) - { - //UpdateCursorState(); - } - - - } - - - - public void UpdateCursorState() - { - if(ActiveWeaponManager == null) - { - drawCursor = false; - //Screen.showCursor = true; - Cursor.visible = true; - return; - } - - if(!GAME_UI_ENABLED || CameraMouseLook.MouseLocked) - { - drawCursor = false; - Cursor.visible = false; - return; - } - - - drawCursor = false; - if(!MapView.MapIsEnabled && !Misc.CheckMouseIsOnGui() && !PauseMenu.isOpen) - { - if(ActiveWeaponManager.weaponIndex > 0 && !ActiveWeaponManager.guardMode) - { - if(ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser) - { - ModuleWeapon mw = ActiveWeaponManager.selectedWeapon.GetPart().FindModuleImplementing(); - if(mw.weaponState == ModuleWeapon.WeaponStates.Enabled && mw.maxPitch > 1 && !mw.slaved && !mw.aiControlled) - { - //Screen.showCursor = false; - Cursor.visible = false; - drawCursor = true; - return; - } - } - else if(ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - RocketLauncher rl = ActiveWeaponManager.selectedWeapon.GetPart().FindModuleImplementing(); - if(rl.readyToFire && rl.turret) - { - //Screen.showCursor = false; - Cursor.visible = false; - drawCursor = true; - return; - } - } - } - } - - //Screen.showCursor = true; - Cursor.visible = true; - } - - - - void VesselChange(Vessel v) - { - if(v.isActiveVessel) - { - GetWeaponManager(); - BDArmorySettings.Instance.UpdateCursorState(); - } - } - - void GetWeaponManager() - { - foreach(var mf in FlightGlobals.ActiveVessel.FindPartModulesImplementing()) - { - ActiveWeaponManager = mf; - return; - } - - ActiveWeaponManager = null; - return; - } - - public static void LoadConfig() - { - try - { - Debug.Log ("== BDArmory : Loading settings.cfg =="); - - BDAPersistantSettingsField.Load(); - BDInputSettingsFields.LoadSettings(); - } - catch(NullReferenceException) - { - Debug.Log ("== BDArmory : Failed to load settings config=="); - } - } - - public static void SaveConfig() - { - try - { - Debug.Log("== BDArmory : Saving settings.cfg == "); - - BDAPersistantSettingsField.Save(); - - BDInputSettingsFields.SaveSettings(); - - if(OnSavedSettings!=null) - { - OnSavedSettings(); - } - - } - catch(NullReferenceException) - { - Debug.Log ("== BDArmory : Failed to save settings.cfg =="); - } - } - - - #region GUI - - void OnGUI() - { - if(GAME_UI_ENABLED) - { - if(settingsGuiEnabled) - { - settingsRect = GUI.Window(129419, settingsRect, SettingsGUI, GUIContent.none); - } - - - if(drawCursor) - { - //mouse cursor - int origDepth = GUI.depth; - GUI.depth = -100; - float cursorSize = 40; - Vector3 cursorPos = Input.mousePosition; - Rect cursorRect = new Rect(cursorPos.x - (cursorSize/2), Screen.height - cursorPos.y - (cursorSize/2), cursorSize, cursorSize); - GUI.DrawTexture(cursorRect, cursorTexture); - GUI.depth = origDepth; - } - - if(toolbarGuiEnabled && HighLogic.LoadedSceneIsFlight) - { - toolbarWindowRect = GUI.Window(321, toolbarWindowRect, ToolbarGUI, "BDA Weapon Manager", HighLogic.Skin.window); - BDGUIUtils.UseMouseEventInRect(toolbarWindowRect); - if(showGPSWindow && ActiveWeaponManager) - { - //gpsWindowRect = GUI.Window(424333, gpsWindowRect, GPSWindow, "", GUI.skin.box); - BDGUIUtils.UseMouseEventInRect(gpsWindowRect); - foreach(var coordinate in BDATargetManager.GPSTargets[BDATargetManager.BoolToTeam(ActiveWeaponManager.team)]) - { - BDGUIUtils.DrawTextureOnWorldPos(coordinate.worldPos, BDArmorySettings.Instance.greenDotTexture, new Vector2(8,8), 0); - } - } - } - } - - - - if(DRAW_DEBUG_LABELS && HighLogic.LoadedSceneIsFlight) - { - if(RadarUtils.radarRT) - { - GUI.DrawTexture(new Rect(20,20,128,128), RadarUtils.radarRT, ScaleMode.StretchToFill, true); - } - } - } - - - public bool hasVS = false; - public bool showVSGUI = false; - - - float rippleHeight = 0; - float weaponsHeight = 0; - float guardHeight = 0; - float modulesHeight = 0; - float gpsHeight = 0; - bool toolMinimized = false; - - void ToolbarGUI(int windowID) - { - GUI.DragWindow(new Rect(30,0,toolWindowWidth-90, 30)); - - float line = 0; - float leftIndent = 10; - float contentWidth = (toolWindowWidth) - (2*leftIndent); - float contentTop = 10; - float entryHeight = 20; - - //GUI.Label(new Rect(leftIndent, contentTop+(line*entryHeight), contentWidth, entryHeight*1.25f), , HighLogic.Skin.label); - /* - if(missileWarning) - { - GUI.Label(new Rect(leftIndent, contentTop+(line*entryHeight), contentWidth, entryHeight), "Missile", leftLabelRed); - GUI.Label(new Rect(leftIndent, contentTop+(line*entryHeight), contentWidth, entryHeight), "Lock", rightLabelRed); - } - */ - line += 1.25f; - line += 0.25f; - - //SETTINGS BUTTON - if(!BDKeyBinder.current && GUI.Button(new Rect(toolWindowWidth - 30, 4, 26, 26), settingsIconTexture, HighLogic.Skin.button)) - { - ToggleSettingsGUI(); - } - - //vesselswitcher button - if(hasVS) - { - GUIStyle vsStyle = showVSGUI ? HighLogic.Skin.box : HighLogic.Skin.button; - if(GUI.Button(new Rect(toolWindowWidth - 30 - 28, 4, 26, 26), "VS", vsStyle)) - { - showVSGUI = !showVSGUI; - } - } - - - if(ActiveWeaponManager!=null) - { - //MINIMIZE BUTTON - toolMinimized = GUI.Toggle(new Rect(4, 4, 26, 26), toolMinimized, "_", toolMinimized ? HighLogic.Skin.box : HighLogic.Skin.button); - - - - GUIStyle armedLabelStyle; - Rect armedRect = new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 2, entryHeight); - if(ActiveWeaponManager.guardMode) - { - if(GUI.Button(armedRect, "- Guard Mode -", HighLogic.Skin.box)) - { - showGuardMenu = true; - } - } - else - { - string armedText = "Trigger is "; - if(ActiveWeaponManager.isArmed) - { - armedText += "ARMED."; - armedLabelStyle = HighLogic.Skin.box; - } - else - { - armedText += "disarmed."; - armedLabelStyle = HighLogic.Skin.button; - } - if(GUI.Button(armedRect, armedText, armedLabelStyle)) - { - ActiveWeaponManager.ToggleArm(); - } - } - - GUIStyle teamButtonStyle; - string teamText = "Team: "; - if(ActiveWeaponManager.team) - { - teamButtonStyle = HighLogic.Skin.box; - teamText += "B"; - } - else - { - teamButtonStyle = HighLogic.Skin.button; - teamText += "A"; - } - - if(GUI.Button(new Rect(leftIndent+(contentWidth/2), contentTop+(line*entryHeight), contentWidth/2, entryHeight), teamText, teamButtonStyle)) - { - ActiveWeaponManager.ToggleTeam(); - } - line++; - line += 0.25f; - string weaponName = ActiveWeaponManager.selectedWeaponString;// = ActiveWeaponManager.selectedWeapon == null ? "None" : ActiveWeaponManager.selectedWeapon.GetShortName(); - string selectionText = "Weapon: "+weaponName; - GUI.Label(new Rect(leftIndent, contentTop+(line*entryHeight), contentWidth, entryHeight*1.25f), selectionText, HighLogic.Skin.box); - line += 1.25f; - line += 0.1f; - //if weapon can ripple, show option and slider. - if(ActiveWeaponManager.hasLoadedRippleData && ActiveWeaponManager.canRipple) - { - if(ActiveWeaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) - { - string rippleText = ActiveWeaponManager.rippleFire ? "Barrage: " + ActiveWeaponManager.gunRippleRpm.ToString("0") + " RPM" : "Salvo"; - GUIStyle rippleStyle = ActiveWeaponManager.rippleFire ? HighLogic.Skin.box : HighLogic.Skin.button; - if(GUI.Button(new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 2, entryHeight * 1.25f), rippleText, rippleStyle)) - { - ActiveWeaponManager.ToggleRippleFire(); - } - - rippleHeight = Mathf.Lerp(rippleHeight, 1.25f, 0.15f); - } - else - { - string rippleText = ActiveWeaponManager.rippleFire ? "Ripple: " + ActiveWeaponManager.rippleRPM.ToString("0") + " RPM" : "Ripple: OFF"; - GUIStyle rippleStyle = ActiveWeaponManager.rippleFire ? HighLogic.Skin.box : HighLogic.Skin.button; - if(GUI.Button(new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 2, entryHeight * 1.25f), rippleText, rippleStyle)) - { - ActiveWeaponManager.ToggleRippleFire(); - } - if(ActiveWeaponManager.rippleFire) - { - Rect sliderRect = new Rect(leftIndent + (contentWidth / 2) + 2, contentTop + (line * entryHeight) + 6.5f, (contentWidth / 2) - 2, 12); - ActiveWeaponManager.rippleRPM = GUI.HorizontalSlider(sliderRect, ActiveWeaponManager.rippleRPM, 100, 1600, rippleSliderStyle, rippleThumbStyle); - } - rippleHeight = Mathf.Lerp(rippleHeight, 1.25f, 0.15f); - } - } - else - { - rippleHeight = Mathf.Lerp(rippleHeight, 0, 0.15f); - } - //line += 1.25f; - line+=rippleHeight; - line += 0.1f; - - if(!toolMinimized) - { - showWeaponList = GUI.Toggle(new Rect(leftIndent, contentTop + (line * entryHeight), contentWidth / 3, entryHeight), showWeaponList, "Weapons", showWeaponList ? HighLogic.Skin.box : HighLogic.Skin.button); - showGuardMenu = GUI.Toggle(new Rect(leftIndent + (contentWidth / 3), contentTop + (line * entryHeight), contentWidth / 3, entryHeight), showGuardMenu, "Guard Menu", showGuardMenu ? HighLogic.Skin.box : HighLogic.Skin.button); - showModules = GUI.Toggle(new Rect(leftIndent + (2 * contentWidth / 3), contentTop + (line * entryHeight), contentWidth / 3, entryHeight), showModules, "Modules", showModules ? HighLogic.Skin.box : HighLogic.Skin.button); - line++; - } - - float weaponLines = 0; - if(showWeaponList && !toolMinimized) - { - line += 0.25f; - Rect weaponListGroupRect = new Rect(5, contentTop + (line * entryHeight), toolWindowWidth - 10, ((float)ActiveWeaponManager.weaponArray.Length+0.1f) * entryHeight); - GUI.BeginGroup(weaponListGroupRect, GUIContent.none, HighLogic.Skin.box); //darker box - weaponLines += 0.1f; - for(int i = 0; i < ActiveWeaponManager.weaponArray.Length; i++) - { - GUIStyle wpnListStyle; - GUIStyle tgtStyle; - if(i == ActiveWeaponManager.weaponIndex) - { - wpnListStyle = middleLeftLabelOrange; - tgtStyle = targetModeStyleSelected; - } - else - { - wpnListStyle = middleLeftLabel; - tgtStyle = targetModeStyle; - } - string label; - string subLabel; - if(ActiveWeaponManager.weaponArray[i] != null) - { - label = ActiveWeaponManager.weaponArray[i].GetShortName(); - subLabel = ActiveWeaponManager.weaponArray[i].GetSubLabel(); - } - else - { - label = "None"; - subLabel = string.Empty; - } - Rect weaponButtonRect = new Rect(leftIndent, (weaponLines * entryHeight), weaponListGroupRect.width - (2*leftIndent), entryHeight); - - GUI.Label(weaponButtonRect, subLabel, tgtStyle); - - if(GUI.Button(weaponButtonRect, label, wpnListStyle)) - { - ActiveWeaponManager.CycleWeapon(i); - } - - - - if(i < ActiveWeaponManager.weaponArray.Length - 1) - { - BDGUIUtils.DrawRectangle(new Rect(weaponButtonRect.x, weaponButtonRect.y + weaponButtonRect.height, weaponButtonRect.width, 1), Color.white); - } - weaponLines++; - } - weaponLines += 0.1f; - GUI.EndGroup(); - } - weaponsHeight = Mathf.Lerp(weaponsHeight, weaponLines, 0.15f); - line += weaponsHeight; - - float guardLines = 0; - if(showGuardMenu && !toolMinimized) - { - line += 0.25f; - GUI.BeginGroup(new Rect(5, contentTop+(line*entryHeight), toolWindowWidth-10, 7.45f*entryHeight), GUIContent.none, HighLogic.Skin.box); - guardLines += 0.1f; - contentWidth -= 16; - leftIndent += 3; - string guardButtonLabel = "Guard Mode " + (ActiveWeaponManager.guardMode ? "ON" : "Off"); - if(GUI.Button(new Rect(leftIndent, (guardLines * entryHeight), contentWidth, entryHeight), guardButtonLabel, ActiveWeaponManager.guardMode ? HighLogic.Skin.box : HighLogic.Skin.button)) - { - ActiveWeaponManager.ToggleGuardMode(); - } - guardLines += 1.25f; - - string scanLabel = ALLOW_LEGACY_TARGETING ? "Scan Interval" : "Firing Interval"; - GUI.Label(new Rect(leftIndent, (guardLines*entryHeight), 85, entryHeight), scanLabel, leftLabel); - ActiveWeaponManager.targetScanInterval = GUI.HorizontalSlider(new Rect(leftIndent+(90), (guardLines*entryHeight), contentWidth-90-38, entryHeight), ActiveWeaponManager.targetScanInterval, 1, 60); - ActiveWeaponManager.targetScanInterval = Mathf.Round(ActiveWeaponManager.targetScanInterval); - GUI.Label(new Rect(leftIndent+(contentWidth-35), (guardLines*entryHeight), 35, entryHeight), ActiveWeaponManager.targetScanInterval.ToString(), leftLabel); - guardLines++; - - GUI.Label(new Rect(leftIndent, (guardLines*entryHeight), 85, entryHeight), "Field of View", leftLabel); - float guardAngle = ActiveWeaponManager.guardAngle; - guardAngle = GUI.HorizontalSlider(new Rect(leftIndent+90, (guardLines*entryHeight), contentWidth-90-38, entryHeight), guardAngle, 10, 360); - guardAngle = guardAngle/10; - guardAngle = Mathf.Round(guardAngle); - ActiveWeaponManager.guardAngle = guardAngle * 10; - GUI.Label(new Rect(leftIndent+(contentWidth-35), (guardLines*entryHeight), 35, entryHeight), ActiveWeaponManager.guardAngle.ToString(), leftLabel); - guardLines++; - - string rangeLabel = ALLOW_LEGACY_TARGETING ? "Guard Range" : "Visual Range"; - GUI.Label(new Rect(leftIndent, (guardLines*entryHeight), 85, entryHeight), rangeLabel, leftLabel); - float guardRange = ActiveWeaponManager.guardRange; - float maxVisRange = ALLOW_LEGACY_TARGETING ? Mathf.Clamp(PHYSICS_RANGE, 2500, 100000) : BDArmorySettings.MAX_GUARD_VISUAL_RANGE; - guardRange = GUI.HorizontalSlider(new Rect(leftIndent+90, (guardLines*entryHeight), contentWidth-90-38, entryHeight), guardRange, 100, maxVisRange); - guardRange = guardRange/100; - guardRange = Mathf.Round(guardRange); - ActiveWeaponManager.guardRange = guardRange * 100; - GUI.Label(new Rect(leftIndent+(contentWidth-35), (guardLines*entryHeight), 35, entryHeight), ActiveWeaponManager.guardRange.ToString(), leftLabel); - guardLines++; - - GUI.Label(new Rect(leftIndent, (guardLines*entryHeight), 85, entryHeight), "Guns Range", leftLabel); - float gRange = ActiveWeaponManager.gunRange; - gRange = GUI.HorizontalSlider(new Rect(leftIndent+90, (guardLines*entryHeight), contentWidth-90-38, entryHeight), gRange, 0, 10000); - gRange /= 100f; - gRange = Mathf.Round(gRange); - gRange *= 100f; - ActiveWeaponManager.gunRange = gRange; - GUI.Label(new Rect(leftIndent+(contentWidth-35), (guardLines*entryHeight), 35, entryHeight), ActiveWeaponManager.gunRange.ToString(), leftLabel); - guardLines++; - - GUI.Label(new Rect(leftIndent, (guardLines*entryHeight), 85, entryHeight), "Missiles/Tgt", leftLabel); - float mslCount = ActiveWeaponManager.maxMissilesOnTarget; - mslCount = GUI.HorizontalSlider(new Rect(leftIndent+90, (guardLines*entryHeight), contentWidth-90-38, entryHeight), mslCount, 1, 6); - mslCount = Mathf.Round(mslCount); - ActiveWeaponManager.maxMissilesOnTarget = mslCount; - GUI.Label(new Rect(leftIndent+(contentWidth-35), (guardLines*entryHeight), 35, entryHeight), ActiveWeaponManager.maxMissilesOnTarget.ToString(), leftLabel); - guardLines++; - - string targetType = "Target Type: "; - if(ActiveWeaponManager.targetMissiles) - { - targetType += "Missiles"; - } - else - { - targetType += "All Targets"; - } - - if(GUI.Button(new Rect(leftIndent, (guardLines*entryHeight), contentWidth, entryHeight), targetType, HighLogic.Skin.button)) - { - ActiveWeaponManager.ToggleTargetType(); - } - guardLines++; - GUI.EndGroup(); - line += 0.1f; - } - guardHeight = Mathf.Lerp(guardHeight, guardLines, 0.15f); - line += guardHeight; - - float moduleLines = 0; - if(showModules && !toolMinimized) - { - line += 0.25f; - GUI.BeginGroup(new Rect(5, contentTop+(line*entryHeight), toolWindowWidth-10, numberOfModules * entryHeight),GUIContent.none, HighLogic.Skin.box); - - numberOfModules = 0; - moduleLines += 0.1f; - //RWR - if(ActiveWeaponManager.rwr) - { - numberOfModules++; - bool isEnabled = ActiveWeaponManager.rwr.rwrEnabled; - string label = "Radar Warning Receiver"; - Rect rwrRect = new Rect(leftIndent, + (moduleLines * entryHeight), contentWidth, entryHeight); - if(GUI.Button(rwrRect, label, isEnabled ? centerLabelOrange : centerLabel)) - { - if(isEnabled) - { - ActiveWeaponManager.rwr.DisableRWR(); - } - else - { - ActiveWeaponManager.rwr.EnableRWR(); - } - } - moduleLines++; - } - - //TGP - foreach(var mtc in ActiveWeaponManager.targetingPods) - { - numberOfModules++; - bool isEnabled = (mtc.cameraEnabled); - bool isActive = (mtc == ModuleTargetingCamera.activeCam); - GUIStyle moduleStyle = isEnabled ? centerLabelOrange : centerLabel;// = mtc - string label = mtc.part.partInfo.title; - if(isActive) - { - moduleStyle = centerLabelRed; - label = "["+label+"]"; - } - if(GUI.Button(new Rect(leftIndent, +(moduleLines*entryHeight), contentWidth, entryHeight), label, moduleStyle)) - { - if(isActive) - { - mtc.ToggleCamera(); - } - else - { - mtc.EnableCamera(); - } - } - moduleLines++; - } - - //RADAR - foreach(var mr in ActiveWeaponManager.radars) - { - numberOfModules++; - GUIStyle moduleStyle = mr.radarEnabled ? centerLabelBlue : centerLabel; - string label = mr.radarName; - if(GUI.Button(new Rect(leftIndent, +(moduleLines*entryHeight), contentWidth, entryHeight), label, moduleStyle)) - { - mr.Toggle(); - } - moduleLines++; - } - - //JAMMERS - foreach(var jammer in ActiveWeaponManager.jammers) - { - if(jammer.alwaysOn) continue; - - numberOfModules++; - GUIStyle moduleStyle = jammer.jammerEnabled ? centerLabelBlue : centerLabel; - string label = jammer.part.partInfo.title; - if(GUI.Button(new Rect(leftIndent, +(moduleLines*entryHeight), contentWidth, entryHeight), label, moduleStyle)) - { - jammer.Toggle(); - } - moduleLines++; - } - - //GPS coordinator - GUIStyle gpsModuleStyle = showGPSWindow ? centerLabelBlue : centerLabel; - numberOfModules++; - if(GUI.Button(new Rect(leftIndent, +(moduleLines*entryHeight), contentWidth, entryHeight), "GPS Coordinator", gpsModuleStyle)) - { - showGPSWindow = !showGPSWindow; - } - moduleLines++; - - //wingCommander - if(ActiveWeaponManager.wingCommander) - { - GUIStyle wingComStyle = ActiveWeaponManager.wingCommander.showGUI ? centerLabelBlue : centerLabel; - numberOfModules++; - if(GUI.Button(new Rect(leftIndent, +(moduleLines*entryHeight), contentWidth, entryHeight), "Wing Command", wingComStyle)) - { - ActiveWeaponManager.wingCommander.ToggleGUI(); - } - moduleLines++; - } - - GUI.EndGroup(); - - line += 0.1f; - } - modulesHeight = Mathf.Lerp(modulesHeight, moduleLines, 0.15f); - line += modulesHeight; - - float gpsLines = 0; - if(showGPSWindow && !toolMinimized) - { - line += 0.25f; - GUI.BeginGroup(new Rect(5, contentTop + (line * entryHeight), toolWindowWidth, gpsWindowRect.height)); - GPSWindow(); - GUI.EndGroup(); - gpsLines = gpsWindowRect.height / entryHeight; - } - gpsHeight = Mathf.Lerp(gpsHeight, gpsLines, 0.15f); - line += gpsHeight; - - } - else - { - GUI.Label(new Rect(leftIndent, contentTop+(line*entryHeight), contentWidth, entryHeight), "No Weapon Manager found.", HighLogic.Skin.box); - line++; - } - - - - - toolWindowHeight = Mathf.Lerp(toolWindowHeight, contentTop + (line*entryHeight) + 5, 1); - toolbarWindowRect.height = toolWindowHeight;// = new Rect(toolbarWindowRect.position.x, toolbarWindowRect.position.y, toolWindowWidth, toolWindowHeight); - } - - bool validGPSName = true; - - //GPS window - void GPSWindow() - { - GUI.Box(gpsWindowRect, GUIContent.none, HighLogic.Skin.box); - gpsEntryCount = 0; - Rect listRect = new Rect(gpsBorder, gpsBorder, gpsWindowRect.width - (2 * gpsBorder), gpsWindowRect.height - (2 * gpsBorder)); - GUI.BeginGroup(listRect); - string targetLabel = "GPS Target: "+ActiveWeaponManager.designatedGPSInfo.name; - GUI.Label(new Rect(0, 0, listRect.width, gpsEntryHeight), targetLabel, kspTitleLabel); - gpsEntryCount+=0.85f; - if(ActiveWeaponManager.designatedGPSCoords != Vector3d.zero) - { - GUI.Label(new Rect(0, gpsEntryCount * gpsEntryHeight, listRect.width - gpsEntryHeight, gpsEntryHeight), Misc.FormattedGeoPos(ActiveWeaponManager.designatedGPSCoords, true), HighLogic.Skin.box); - if(GUI.Button(new Rect(listRect.width - gpsEntryHeight, gpsEntryCount * gpsEntryHeight, gpsEntryHeight, gpsEntryHeight), "X", HighLogic.Skin.button)) - { - ActiveWeaponManager.designatedGPSInfo = new GPSTargetInfo(); - } - } - else - { - GUI.Label(new Rect(0, gpsEntryCount * gpsEntryHeight, listRect.width - gpsEntryHeight, gpsEntryHeight), "No Target", HighLogic.Skin.box); - } - gpsEntryCount+=1.35f; - int indexToRemove = -1; - int index = 0; - BDATeams myTeam = BDATargetManager.BoolToTeam(ActiveWeaponManager.team); - foreach(var coordinate in BDATargetManager.GPSTargets[myTeam]) - { - Color origWColor = GUI.color; - if(coordinate.EqualsTarget(ActiveWeaponManager.designatedGPSInfo)) - { - GUI.color = XKCDColors.LightOrange; - } - string label = Misc.FormattedGeoPosShort(coordinate.gpsCoordinates, false); - float nameWidth = 100; - if(editingGPSName && index == editingGPSNameIndex) - { - if(validGPSName && Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return) - { - editingGPSName = false; - hasEnteredGPSName = true; - } - else - { - Color origColor = GUI.color; - if(newGPSName.Contains(";") || newGPSName.Contains(":") || newGPSName.Contains(",")) - { - validGPSName = false; - GUI.color = Color.red; - } - else - { - validGPSName = true; - } - newGPSName = GUI.TextField(new Rect(0, gpsEntryCount * gpsEntryHeight, nameWidth, gpsEntryHeight), newGPSName, 12); - GUI.color = origColor; - } - } - else - { - if(GUI.Button(new Rect(0, gpsEntryCount * gpsEntryHeight, nameWidth, gpsEntryHeight), coordinate.name, HighLogic.Skin.button)) - { - editingGPSName = true; - editingGPSNameIndex = index; - newGPSName = coordinate.name; - } - } - if(GUI.Button(new Rect(nameWidth, gpsEntryCount * gpsEntryHeight, listRect.width - gpsEntryHeight - nameWidth, gpsEntryHeight), label, HighLogic.Skin.button)) - { - ActiveWeaponManager.designatedGPSInfo = coordinate; - editingGPSName = false; - } - if(GUI.Button(new Rect(listRect.width - gpsEntryHeight, gpsEntryCount * gpsEntryHeight, gpsEntryHeight, gpsEntryHeight), "X", HighLogic.Skin.button)) - { - indexToRemove = index; - } - gpsEntryCount++; - index++; - GUI.color = origWColor; - } - if(hasEnteredGPSName && editingGPSNameIndex < BDATargetManager.GPSTargets[myTeam].Count) - { - hasEnteredGPSName = false; - GPSTargetInfo old = BDATargetManager.GPSTargets[myTeam][editingGPSNameIndex]; - if(ActiveWeaponManager.designatedGPSInfo.EqualsTarget(old)) - { - ActiveWeaponManager.designatedGPSInfo.name = newGPSName; - } - BDATargetManager.GPSTargets[myTeam][editingGPSNameIndex] = new GPSTargetInfo(BDATargetManager.GPSTargets[myTeam][editingGPSNameIndex].gpsCoordinates, newGPSName); - editingGPSNameIndex = 0; - } - - GUI.EndGroup(); - - if(indexToRemove >= 0) - { - BDATargetManager.GPSTargets[myTeam].RemoveAt(indexToRemove); - } - - //gpsWindowRect.x = toolbarWindowRect.x; - //gpsWindowRect.y = toolbarWindowRect.y + toolbarWindowRect.height; - gpsWindowRect.height = (2*gpsBorder) + (gpsEntryCount * gpsEntryHeight); - } - - - - - - - Rect SLineRect(float line) - { - return new Rect(settingsMargin, line * settingsLineHeight, settingsWidth - (2 * settingsMargin), settingsLineHeight); - } - - Rect SRightRect(float line) - { - return new Rect(settingsMargin + ((settingsWidth - 2 * settingsLineHeight) / 2), line * settingsLineHeight, (settingsWidth - (2 * settingsMargin)) / 2, settingsLineHeight); - } - - Rect SLeftRect(float line) - { - return new Rect(settingsMargin, (line * settingsLineHeight), (settingsWidth - (2*settingsMargin))/2, settingsLineHeight); - } - - float settingsWidth; - float settingsHeight; - float settingsLeft; - float settingsTop; - float settingsLineHeight; - float settingsMargin; - Rect settingsRect; - bool editKeys = false; - void SetupSettingsSize() - { - settingsWidth = 420; - settingsHeight = 480; - settingsLeft = Screen.width/2 - settingsWidth/2; - settingsTop = 100; - settingsLineHeight = 22; - settingsMargin = 18; - settingsRect = new Rect(settingsLeft, settingsTop, settingsWidth, settingsHeight); - } - - void SettingsGUI(int windowID) - { - float line = 1.25f; - GUI.Box(new Rect(0, 0, settingsWidth, settingsHeight), "BDArmory Settings"); - GUI.DragWindow(new Rect(0,0,settingsWidth, 25)); - if(editKeys) - { - InputSettings(); - return; - } - INSTAKILL = GUI.Toggle(SLeftRect(line), INSTAKILL, "Instakill"); - INFINITE_AMMO = GUI.Toggle(SRightRect(line), INFINITE_AMMO, "Infinte Ammo"); - line++; - BULLET_HITS = GUI.Toggle(SLeftRect(line), BULLET_HITS, "Bullet Hits"); - EJECT_SHELLS = GUI.Toggle(SRightRect(line), EJECT_SHELLS, "Eject Shells"); - line++; - AIM_ASSIST = GUI.Toggle(SLeftRect(line), AIM_ASSIST, "Aim Assist"); - DRAW_AIMERS = GUI.Toggle(SRightRect(line), DRAW_AIMERS, "Draw Aimers"); - line++; - DRAW_DEBUG_LINES = GUI.Toggle(SLeftRect(line), DRAW_DEBUG_LINES, "Debug Lines"); - DRAW_DEBUG_LABELS = GUI.Toggle(SRightRect(line), DRAW_DEBUG_LABELS, "Debug Labels"); - line++; - REMOTE_SHOOTING = GUI.Toggle(SLeftRect(line), REMOTE_SHOOTING, "Remote Firing"); - BOMB_CLEARANCE_CHECK = GUI.Toggle(SRightRect(line), BOMB_CLEARANCE_CHECK, "Clearance Check"); - line++; - ALLOW_LEGACY_TARGETING = GUI.Toggle(SLeftRect(line), ALLOW_LEGACY_TARGETING, "Legacy Targeting"); - SHELL_COLLISIONS = GUI.Toggle(SRightRect(line), SHELL_COLLISIONS, "Shell Collisions"); - line++; - line++; - - bool origPm = PEACE_MODE; - PEACE_MODE = GUI.Toggle(SLeftRect(line), PEACE_MODE, "Peace Mode"); - if(PEACE_MODE && !origPm) - { - BDATargetManager.ClearDatabase(); - if(OnPeaceEnabled != null) - { - OnPeaceEnabled(); - } - } - line++; - line++; - - - GUI.Label(SLeftRect(line), "Trigger Hold: "+TRIGGER_HOLD_TIME.ToString("0.00")+"s", leftLabel); - TRIGGER_HOLD_TIME = GUI.HorizontalSlider(SRightRect(line),TRIGGER_HOLD_TIME, 0.02f, 1f); - line++; - - - GUI.Label(SLeftRect(line), "UI Volume: "+(BDARMORY_UI_VOLUME*100).ToString("0"), leftLabel); - float uiVol = BDARMORY_UI_VOLUME; - uiVol = GUI.HorizontalSlider(SRightRect(line),uiVol, 0f, 1f); - if(uiVol != BDARMORY_UI_VOLUME && OnVolumeChange != null) - { - OnVolumeChange(); - } - BDARMORY_UI_VOLUME = uiVol; - line++; - - GUI.Label(SLeftRect(line), "Weapon Volume: "+(BDARMORY_WEAPONS_VOLUME*100).ToString("0"), leftLabel); - float weaponVol = BDARMORY_WEAPONS_VOLUME; - weaponVol = GUI.HorizontalSlider(SRightRect(line),weaponVol, 0f, 1f); - if(uiVol != BDARMORY_WEAPONS_VOLUME && OnVolumeChange != null) - { - OnVolumeChange(); - } - BDARMORY_WEAPONS_VOLUME = weaponVol; - line++; - line++; - - physicsRangeGui = GUI.TextField(SRightRect(line), physicsRangeGui); - GUI.Label(SLeftRect(line), "Physics Load Distance", leftLabel); - line++; - GUI.Label(SLeftRect(line), "Warning: Risky if set high", centerLabel); - if(GUI.Button(SRightRect(line), "Apply Phys Distance")) - { - float physRangeSetting = float.Parse(physicsRangeGui); - PHYSICS_RANGE = (physRangeSetting>=2500 ? Mathf.Clamp(physRangeSetting, 2500, 100000) : 0); - physicsRangeGui = PHYSICS_RANGE.ToString(); - ApplyPhysRange(); - } - line++; - line++; - - //competition mode - if(HighLogic.LoadedSceneIsFlight) - { - GUI.Label(SLineRect(line), "= Dogfight Competition =", centerLabel); - line++; - if(!BDACompetitionMode.Instance.competitionStarting) - { - compDistGui = GUI.TextField(SRightRect(line), compDistGui); - GUI.Label(SLeftRect(line), "Competition Distance"); - float cDist; - if(float.TryParse(compDistGui, out cDist)) - { - competitionDist = cDist; - } - line++; - - if(GUI.Button(SRightRect(line), "Start Competition")) - { - competitionDist = Mathf.Clamp(competitionDist, 2000f, 20000f); - compDistGui = competitionDist.ToString(); - BDACompetitionMode.Instance.StartCompetitionMode(competitionDist); - SaveConfig(); - settingsGuiEnabled = false; - } - } - else - { - GUI.Label(SLeftRect(line), "Starting Competition... (" + compDistGui + ")"); - line++; - if(GUI.Button(SLeftRect(line), "Cancel")) - { - BDACompetitionMode.Instance.StopCompetition(); - } - } - } - - line++; - line++; - if(GUI.Button(SLineRect(line), "Edit Inputs")) - { - editKeys = true; - } - line++; - line++; - if(!BDKeyBinder.current && GUI.Button(SLineRect(line), "Save and Close")) - { - SaveConfig(); - settingsGuiEnabled = false; - } - - line+=1.5f; - settingsHeight = (line * settingsLineHeight); - settingsRect.height = settingsHeight; - BDGUIUtils.UseMouseEventInRect(settingsRect); - } - - void InputSettings() - { - float line = 1.25f; - int inputID = 0; - - - GUI.Label(SLineRect(line), "- Weapons -", centerLabel); - line++; - InputSettingsList("WEAP_", ref inputID, ref line); - line++; - - GUI.Label(SLineRect(line), "- Targeting Pod -", centerLabel); - line++; - InputSettingsList("TGP_", ref inputID, ref line); - line++; - - GUI.Label(SLineRect(line), "- Radar -", centerLabel); - line++; - InputSettingsList("RADAR_", ref inputID, ref line); - - line += 2; - if(!BDKeyBinder.current && GUI.Button(SLineRect(line), "Back")) - { - editKeys = false; - } - - line+=1.5f; - settingsHeight = (line * settingsLineHeight); - settingsRect.height = settingsHeight; - BDGUIUtils.UseMouseEventInRect(settingsRect); - } - - void InputSettingsList(string prefix, ref int id, ref float line) - { - if(inputFields != null) - { - for(int i = 0; i < inputFields.Length; i++) - { - string fieldName = inputFields[i].Name; - if(fieldName.StartsWith(prefix, StringComparison.Ordinal)) - { - InputSettingsLine(fieldName, id++, ref line); - } - } - } - } - - void InputSettingsLine(string fieldName, int id, ref float line) - { - GUI.Box(SLineRect(line), GUIContent.none); - string label = string.Empty; - if(BDKeyBinder.IsRecordingID(id)) - { - string recordedInput; - if(BDKeyBinder.current.AcquireInputString(out recordedInput)) - { - BDInputInfo orig = (BDInputInfo)typeof(BDInputSettingsFields).GetField(fieldName).GetValue(null); - BDInputInfo recorded = new BDInputInfo(recordedInput, orig.description); - typeof(BDInputSettingsFields).GetField(fieldName).SetValue(null, recorded); - } - - label = " Press a key or button."; - } - else - { - BDInputInfo inputInfo = new BDInputInfo(); - try - { - inputInfo = (BDInputInfo)typeof(BDInputSettingsFields).GetField(fieldName).GetValue(null); - - } - catch(NullReferenceException) - { - Debug.Log("Reflection failed to find input info of field: " + fieldName); - editKeys = false; - return; - } - label = " "+inputInfo.description+" : "+inputInfo.inputString; - - if(GUI.Button(SSetKeyRect(line), "Set Key")) - { - BDKeyBinder.BindKey(id); - } - if(GUI.Button(SClearKeyRect(line), "Clear")) - { - typeof(BDInputSettingsFields).GetField(fieldName).SetValue(null, new BDInputInfo(inputInfo.description)); - } - } - GUI.Label(SLeftRect(line), label); - line++; - } - - Rect SSetKeyRect(float line) - { - return new Rect(settingsMargin + (2*(settingsWidth - 2 * settingsMargin) / 3), line * settingsLineHeight, (settingsWidth - (2 * settingsMargin)) / 6, settingsLineHeight); - } - - Rect SClearKeyRect(float line) - { - return new Rect(settingsMargin + (2*(settingsWidth - 2 * settingsMargin) / 3) + (settingsWidth - 2 * settingsMargin) / 6, line * settingsLineHeight, (settingsWidth - (2 * settingsMargin)) / 6, settingsLineHeight); - } - - #endregion - - public void ApplyPhysRange() - { - - if(PHYSICS_RANGE <= 2500) PHYSICS_RANGE = 0; - - - - if(!HighLogic.LoadedSceneIsFlight) - { - return; - } - - - if(PHYSICS_RANGE > 0) - { - float pack = PHYSICS_RANGE; - float unload = PHYSICS_RANGE * 0.9f; - float load = unload * 0.9f; - float unpack = load * 0.9f; - - VesselRanges defaultRanges = PhysicsGlobals.Instance.VesselRangesDefault; - VesselRanges.Situation combatSituation = new VesselRanges.Situation(load, unload, pack, unpack); - - - - VesselRanges.Situation combatFlyingSituation = ClampedSituation(combatSituation, defaultRanges.flying); - VesselRanges.Situation combatLandedSituation = ClampedSituationLanded(combatSituation, defaultRanges.landed); - VesselRanges.Situation combatSplashedSituation = ClampedSituation(combatSituation, defaultRanges.splashed); - VesselRanges.Situation combatOrbitSituation = ClampedSituation(combatSituation, defaultRanges.orbit); - VesselRanges.Situation combatSubOrbitSituation = ClampedSituation(combatSituation, defaultRanges.subOrbital); - VesselRanges.Situation combatPrelaunchSituation = ClampedSituation(combatSituation, defaultRanges.prelaunch); - - combatVesselRanges.flying = combatFlyingSituation; - combatVesselRanges.landed = combatLandedSituation; - combatVesselRanges.splashed = combatSplashedSituation; - combatVesselRanges.orbit = combatOrbitSituation; - combatVesselRanges.subOrbital = combatSubOrbitSituation; - combatVesselRanges.prelaunch = combatPrelaunchSituation; - - foreach(Vessel v in FlightGlobals.Vessels) - { - v.vesselRanges = new VesselRanges(combatVesselRanges); - } - - FloatingOrigin.fetch.threshold = Mathf.Pow(PHYSICS_RANGE + 3500, 2); - } - else - { - foreach(Vessel v in FlightGlobals.Vessels) - { - v.vesselRanges = PhysicsGlobals.Instance.VesselRangesDefault; - } - - FloatingOrigin.fetch.threshold = Mathf.Pow(6000, 2); - } - } - - private VesselRanges.Situation ClampedSituation(VesselRanges.Situation input, VesselRanges.Situation minSituation) - { - float load = Mathf.Clamp(input.load, minSituation.load, 81000); - float unload = Mathf.Clamp(input.unload, minSituation.unload, 90000); - float pack = Mathf.Clamp(input.pack, minSituation.pack, 100000); - float unpack = Mathf.Clamp(input.unpack, minSituation.unpack, 72900); - - VesselRanges.Situation output = new VesselRanges.Situation(load, unload, pack, unpack); - return output; - - } - - private VesselRanges.Situation ClampedSituationLanded(VesselRanges.Situation input, VesselRanges.Situation minSituation) - { - float maxLanded = 11000; - float load = Mathf.Clamp(input.load, minSituation.load, maxLanded*.9f*.9f); - float unload = Mathf.Clamp(input.unload, minSituation.unload, maxLanded*.9f); - float pack = Mathf.Clamp(input.pack, minSituation.pack, maxLanded); - float unpack = Mathf.Clamp(input.unpack, minSituation.unpack, maxLanded*.9f*.9f*.9f); - - VesselRanges.Situation output = new VesselRanges.Situation(load, unload, pack, unpack); - return output; - } - - public void ApplyNewVesselRanges(Vessel v) - { - v.vesselRanges = new VesselRanges(combatVesselRanges); - } - - void HideGameUI() - { - GAME_UI_ENABLED = false; - } - - void ShowGameUI() - { - GAME_UI_ENABLED = true; - } - - - - - - void OnVesselGoOffRails(Vessel v) - { - if(v.Landed && BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log ("Loaded vessel: "+v.vesselName+", Velocity: "+v.srf_velocity+", packed: "+v.packed); - //v.SetWorldVelocity(Vector3d.zero); - } - } - - public void SaveVolumeSettings() - { - SeismicChargeFX.originalShipVolume = GameSettings.SHIP_VOLUME; - SeismicChargeFX.originalMusicVolume = GameSettings.MUSIC_VOLUME; - SeismicChargeFX.originalAmbienceVolume = GameSettings.AMBIENCE_VOLUME; - } - - } -} - diff --git a/BahaTurret/BDExplosivePart.cs b/BahaTurret/BDExplosivePart.cs deleted file mode 100644 index 46387cdef..000000000 --- a/BahaTurret/BDExplosivePart.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class BDExplosivePart : PartModule - { - - [KSPField(isPersistant = false)] - public float blastRadius = 50; - [KSPField(isPersistant = false)] - public float blastPower = 25; - - [KSPField] - public float blastHeat = -1; - - [KSPAction("Detonate")] - public void DetonateAG(KSPActionParam param) - { - Detonate (); - } - - - /* - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Proxy Detonate")] - public bool proximityDetonation = false; - */ - - //public GameObject target = null; - - // bool hasFired = false; - bool hasDetonated = false; - - public override void OnStart (PartModule.StartState state) - { - part.OnJustAboutToBeDestroyed += new Callback(Detonate); - part.force_activate(); - - } - - public override void OnFixedUpdate() - { - /* - if(hasFired && proximityDetonation && Vector3.Distance(target.transform.position, transform.position+rigidbody.velocity*Time.fixedDeltaTime) < blastRadius/2) - { - Detonate(); - } - */ - } - - public void Detonate() - { - if(!hasDetonated) - { - hasDetonated = true; - if(part!=null) part.temperature = part.maxTemp + 100; - Vector3 position = transform.position+part.rb.velocity*Time.fixedDeltaTime; - ExplosionFX.CreateExplosion(position, blastRadius, blastPower, blastHeat, vessel, FlightGlobals.getUpAxis(), "BDArmory/Models/explosion/explosionLarge", "BDArmory/Sounds/explode1"); - } - } - } -} - diff --git a/BahaTurret/BDGUIUtils.cs b/BahaTurret/BDGUIUtils.cs deleted file mode 100644 index 54dde242a..000000000 --- a/BahaTurret/BDGUIUtils.cs +++ /dev/null @@ -1,147 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; -namespace BahaTurret -{ - public static class BDGUIUtils - { - public static Texture2D pixel; - - public static Camera GetMainCamera() - { - if(HighLogic.LoadedSceneIsFlight) - { - return FlightCamera.fetch.mainCamera; - } - else - { - return Camera.main; - } - } - - public static void DrawTextureOnWorldPos(Vector3 worldPos, Texture texture, Vector2 size, float wobble) - { - Vector3 screenPos = GetMainCamera().WorldToViewportPoint(worldPos); - if(screenPos.z < 0) return; //dont draw if point is behind camera - if(screenPos.x != Mathf.Clamp01(screenPos.x)) return; //dont draw if off screen - if(screenPos.y != Mathf.Clamp01(screenPos.y)) return; - float xPos = screenPos.x*Screen.width-(0.5f*size.x); - float yPos = (1-screenPos.y)*Screen.height-(0.5f*size.y); - if(wobble > 0) - { - xPos += UnityEngine.Random.Range(-wobble/2, wobble/2); - yPos += UnityEngine.Random.Range(-wobble/2, wobble/2); - } - Rect iconRect = new Rect(xPos, yPos, size.x, size.y); - - GUI.DrawTexture(iconRect, texture); - } - - public static bool WorldToGUIPos(Vector3 worldPos, out Vector2 guiPos) - { - Vector3 screenPos = GetMainCamera().WorldToViewportPoint(worldPos); - bool offScreen = false; - if(screenPos.z < 0) offScreen = true; //dont draw if point is behind camera - if(screenPos.x != Mathf.Clamp01(screenPos.x)) offScreen = true; //dont draw if off screen - if(screenPos.y != Mathf.Clamp01(screenPos.y)) offScreen = true; - if(!offScreen) - { - float xPos = screenPos.x * Screen.width; - float yPos = (1 - screenPos.y) * Screen.height; - guiPos = new Vector2(xPos, yPos); - return true; - } - else - { - guiPos = Vector2.zero; - return false; - } - } - - public static void DrawLineBetweenWorldPositions(Vector3 worldPosA, Vector3 worldPosB, float width, Color color) - { - Camera cam = GetMainCamera(); - GUI.matrix = Matrix4x4.identity; - - bool aBehind = false; - - Plane clipPlane = new Plane(cam.transform.forward, cam.transform.position + cam.transform.forward * 0.05f); - - if(Vector3.Dot(cam.transform.forward, worldPosA-cam.transform.position) < 0) - { - Ray ray = new Ray(worldPosB, worldPosA - worldPosB); - float dist; - if(clipPlane.Raycast(ray, out dist)) - { - worldPosA = ray.GetPoint(dist); - } - aBehind = true; - } - if(Vector3.Dot(cam.transform.forward, worldPosB-cam.transform.position) < 0) - { - if(aBehind) return; - - Ray ray = new Ray(worldPosA, worldPosB - worldPosA); - float dist; - if(clipPlane.Raycast(ray, out dist)) - { - worldPosB = ray.GetPoint(dist); - } - } - - Vector3 screenPosA = cam.WorldToViewportPoint(worldPosA); - screenPosA.x = screenPosA.x*Screen.width; - screenPosA.y = (1-screenPosA.y)*Screen.height; - Vector3 screenPosB = cam.WorldToViewportPoint(worldPosB); - screenPosB.x = screenPosB.x*Screen.width; - screenPosB.y = (1-screenPosB.y)*Screen.height; - - screenPosA.z = screenPosB.z = 0; - - float angle = Vector2.Angle(Vector3.up, screenPosB - screenPosA); - if(screenPosB.x < screenPosA.x) - { - angle = -angle; - } - - Vector2 vector = screenPosB - screenPosA; - float length = vector.magnitude; - - Rect upRect = new Rect(screenPosA.x - (width / 2), screenPosA.y-length, width, length); - - GUIUtility.RotateAroundPivot(-angle+180, screenPosA); - DrawRectangle(upRect, color); - GUI.matrix = Matrix4x4.identity; - } - - public static void DrawRectangle(Rect rect, Color color) - { - if(pixel == null) - { - pixel = new Texture2D(1,1); - } - - Color originalColor = GUI.color; - GUI.color = color; - GUI.DrawTexture(rect, pixel); - GUI.color = originalColor; - } - - public static void UseMouseEventInRect(Rect rect) - { - if(Misc.MouseIsInRect(rect) && Event.current.isMouse && (Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseUp)) - { - Event.current.Use(); - } - } - } -} - diff --git a/BahaTurret/BDInputInfo.cs b/BahaTurret/BDInputInfo.cs deleted file mode 100644 index 4a23a8a0e..000000000 --- a/BahaTurret/BDInputInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace BahaTurret -{ - public struct BDInputInfo - { - public string description; - public string inputString; - - public BDInputInfo(string description) - { - this.description = description; - this.inputString = string.Empty; - } - - public BDInputInfo(string inputString, string description) - { - this.inputString = inputString; - this.description = description; - } - } -} - diff --git a/BahaTurret/BDInputSettingsFields.cs b/BahaTurret/BDInputSettingsFields.cs deleted file mode 100644 index 9f69d4f2d..000000000 --- a/BahaTurret/BDInputSettingsFields.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Reflection; -using UnityEngine; - - -namespace BahaTurret -{ - public class BDInputSettingsFields - { - //MAIN - public static BDInputInfo WEAP_FIRE_KEY = new BDInputInfo("mouse 0", "Fire"); - //TGP - public static BDInputInfo TGP_SLEW_RIGHT = new BDInputInfo("Slew Right"); - public static BDInputInfo TGP_SLEW_LEFT = new BDInputInfo("Slew Left"); - public static BDInputInfo TGP_SLEW_UP = new BDInputInfo("Slew Up"); - public static BDInputInfo TGP_SLEW_DOWN = new BDInputInfo("Slew Down"); - public static BDInputInfo TGP_LOCK = new BDInputInfo("Lock/Unlock"); - public static BDInputInfo TGP_IN = new BDInputInfo("Zoom In"); - public static BDInputInfo TGP_OUT = new BDInputInfo("Zoom Out"); - public static BDInputInfo TGP_RADAR = new BDInputInfo("To Radar"); - public static BDInputInfo TGP_SEND_GPS = new BDInputInfo("Send GPS"); - public static BDInputInfo TGP_TO_GPS = new BDInputInfo("Slave to GPS"); - public static BDInputInfo TGP_TURRETS = new BDInputInfo("Slave Turrets"); - public static BDInputInfo TGP_COM = new BDInputInfo("CoM-Track"); - public static BDInputInfo TGP_NV = new BDInputInfo("Toggle NV"); - public static BDInputInfo TGP_RESET = new BDInputInfo("Reset"); - - //RADAR - public static BDInputInfo RADAR_LOCK = new BDInputInfo("Lock/Unlock"); - public static BDInputInfo RADAR_CYCLE_LOCK = new BDInputInfo("Cycle Lock"); - public static BDInputInfo RADAR_SLEW_RIGHT = new BDInputInfo("Slew Right"); - public static BDInputInfo RADAR_SLEW_LEFT = new BDInputInfo("Slew Left"); - public static BDInputInfo RADAR_SLEW_UP = new BDInputInfo("Slew Up"); - public static BDInputInfo RADAR_SLEW_DOWN = new BDInputInfo("Slew Down"); - public static BDInputInfo RADAR_SCAN_MODE = new BDInputInfo("Scan Mode"); - public static BDInputInfo RADAR_TURRETS = new BDInputInfo("Slave Turrets"); - public static BDInputInfo RADAR_RANGE_UP = new BDInputInfo("Range +"); - public static BDInputInfo RADAR_RANGE_DN = new BDInputInfo("Range -"); - - - public static void SaveSettings() - { - ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); - if(!fileNode.HasNode("BDAInputSettings")) - { - fileNode.AddNode("BDAInputSettings"); - } - - ConfigNode cfg = fileNode.GetNode("BDAInputSettings"); - - FieldInfo[] fields = typeof(BDInputSettingsFields).GetFields(); - for(int i = 0; i < fields.Length; i++) - { - string fieldName = fields[i].Name; - string valueString = ((BDInputInfo)fields[i].GetValue(null)).inputString; - cfg.SetValue(fieldName, valueString, true); - } - - fileNode.Save(BDArmorySettings.settingsConfigURL); - } - - public static void LoadSettings() - { - ConfigNode fileNode = ConfigNode.Load(BDArmorySettings.settingsConfigURL); - if(!fileNode.HasNode("BDAInputSettings")) - { - fileNode.AddNode("BDAInputSettings"); - } - - ConfigNode cfg = fileNode.GetNode("BDAInputSettings"); - - FieldInfo[] fields = typeof(BDInputSettingsFields).GetFields(); - for(int i = 0; i < fields.Length; i++) - { - string fieldName = fields[i].Name; - if(cfg.HasValue(fieldName)) - { - BDInputInfo orig = (BDInputInfo)fields[i].GetValue(null); - BDInputInfo loaded = new BDInputInfo(cfg.GetValue(fieldName), orig.description); - fields[i].SetValue(null, loaded); - } - } - - fileNode.Save(BDArmorySettings.settingsConfigURL); - } - } -} - diff --git a/BahaTurret/BDInputUtils.cs b/BahaTurret/BDInputUtils.cs deleted file mode 100644 index 5268623c9..000000000 --- a/BahaTurret/BDInputUtils.cs +++ /dev/null @@ -1,175 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class BDInputUtils - { - public static string GetInputString() - { - //keyCodes - string[] names = System.Enum.GetNames(typeof(KeyCode)); - int numberOfKeycodes = names.Length; - - for(int i = 0; i < numberOfKeycodes; i++) - { - string output = names[i]; - - if(output.Contains("Keypad")) - { - output = "["+output.Substring(6).ToLower()+"]"; - } - else if(output.Contains("Alpha")) - { - output = output.Substring(5); - } - else //lower case key - { - output = output.ToLower(); - } - - //modifiers - if(output.Contains("control")) - { - output = output.Split('c')[0] + " ctrl"; - } - else if(output.Contains("alt")) - { - output = output.Split('a')[0] + " alt"; - } - else if(output.Contains("shift")) - { - output = output.Split ('s')[0] + " shift"; - } - else if(output.Contains("command")) - { - output = output.Split('c')[0]+" cmd"; - } - - - //special keys - else if(output == "backslash") - { - output = @"\"; - } - else if(output == "backquote") - { - output = "`"; - } - else if(output == "[period]") - { - output = "[.]"; - } - else if(output == "[plus]") - { - output = "[+]"; - } - else if(output == "[multiply]") - { - output = "[*]"; - } - else if(output == "[divide]") - { - output = "[/]"; - } - else if(output == "[minus]") - { - output = "[-]"; - } - else if(output == "[enter]") - { - output = "enter"; - } - else if(output.Contains("page")) - { - output = output.Insert(4, " "); - } - else if(output.Contains("arrow")) - { - output = output.Split('a')[0]; - } - else if(output == "capslock") - { - output = "caps lock"; - } - else if(output == "minus") - { - output = "-"; - } - - //test if input is valid - try - { - if(Input.GetKey(output)) - { - return output; - } - } - catch(System.Exception) - { - } - - } - - //mouse - for(int m = 0; m < 6; m++) - { - string inputString = "mouse "+m; - try - { - if(Input.GetKey(inputString)) - { - return inputString; - } - } - catch(UnityException) - { - Debug.Log ("Invalid mouse: "+inputString); - } - } - - //joysticks - for(int j = 1; j < 12; j++) - { - for(int b = 0; b<20; b++) - { - string inputString = "joystick "+j+" button "+b; - try - { - if(Input.GetKey(inputString)) - { - return inputString; - } - } - catch(UnityException) - { - return string.Empty; - } - - } - } - - return string.Empty; - } - - public static bool GetKey(BDInputInfo input) - { - return input.inputString != string.Empty && Input.GetKey(input.inputString); - } - - public static bool GetKeyDown(BDInputInfo input) - { - return input.inputString != string.Empty && Input.GetKeyDown(input.inputString); - } - } -} - diff --git a/BahaTurret/BDKeyBinder.cs b/BahaTurret/BDKeyBinder.cs deleted file mode 100644 index c5661cd63..000000000 --- a/BahaTurret/BDKeyBinder.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; -namespace BahaTurret -{ - public class BDKeyBinder : MonoBehaviour - { - public static BDKeyBinder current = null; - public int id = 0; - public bool valid = false; - string inputString = string.Empty; - bool mouseUp = false; - - public void StartRecording() - { - StartCoroutine(RecordKeyRoutine()); - } - - IEnumerator RecordKeyRoutine() - { - while(!valid) - { - if(mouseUp) - { - string iString = BDInputUtils.GetInputString(); - if(iString.Length > 0) - { - inputString = iString; - valid = true; - } - } - - if(Input.GetKeyUp(KeyCode.Mouse0)) - { - mouseUp = true; - } - yield return null; - } - } - - public bool AcquireInputString(out string _inputString) - { - if(valid) - { - _inputString = inputString; - current = null; - Destroy(gameObject); - return true; - } - else - { - _inputString = string.Empty; - return false; - } - } - - public static void BindKey(int id) - { - if(current != null) - { - Debug.Log("Tried to bind key but key binder is in use."); - return; - } - - current = new GameObject().AddComponent(); - current.id = id; - current.StartRecording(); - } - - public static bool IsRecordingID(int id) - { - return (current && current.id == id); - } - } -} - diff --git a/BahaTurret/BDMMLauncher.cs b/BahaTurret/BDMMLauncher.cs deleted file mode 100644 index c752cd2a9..000000000 --- a/BahaTurret/BDMMLauncher.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - - -namespace BahaTurret -{ - public class BDMMLauncher : PartModule - { - - public override void OnStart (PartModule.StartState state) - { - part.force_activate(); - } - - [KSPEvent(name = "Fire", guiActive = true, active = true)] - public void Fire() - { - - - GameObject target = null; - if(vessel.targetObject!=null) target = vessel.targetObject.GetVessel().gameObject; - - part.decouple(0); - - - - foreach(var bdmm in vessel.FindPartModulesImplementing()) - { - bdmm.hasFired = true; - //bdmm.target = target; - } - foreach(var bde in vessel.FindPartModulesImplementing()) - { - //bde.target = target; - } - } - - } -} - diff --git a/BahaTurret/BDModularGuidance.cs b/BahaTurret/BDModularGuidance.cs deleted file mode 100644 index 367bc690a..000000000 --- a/BahaTurret/BDModularGuidance.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class BDModularGuidance : PartModule - { - //public GameObject target = null; - - public bool hasFired = false; - - public bool guidanceActive = false; - - Vessel targetVessel; - Vessel parentVessel; - - Transform vesselTransform; - Transform velocityTransform; - - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "SteerFactor"), - UI_FloatRange(minValue = 0.1f, maxValue = 20f, stepIncrement = .1f, scene = UI_Scene.All)] - public float steerMult = 10; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "SteerLimiter"), - UI_FloatRange(minValue = .1f, maxValue = 1f, stepIncrement = .05f, scene = UI_Scene.All)] - public float maxSteer = 1; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "SteerDamping"), - UI_FloatRange(minValue = 0f, maxValue = 20f, stepIncrement = .05f, scene = UI_Scene.All)] - public float steerDamping = 5; - - [KSPField(isPersistant = true)] - public int guidanceMode = 1; - [KSPField(guiActive = true, guiName = "Guidance Type ", guiActiveEditor = true)] - public string guidanceLabel = "AAM"; - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "CruiseAltitude"), - UI_FloatRange(minValue = 50f, maxValue = 1500f, stepIncrement = 50f, scene = UI_Scene.All)] - public float cruiseAltitude = 500; - - - public float timeToImpact; - - [KSPAction("Start Guidance")] - public void AGStartGuidance(KSPActionParam param) - { - StartGuidance(); - } - - [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "Start Guidance", active = true)] - public void StartGuidance() - { - if(hasFired) - { - return; - } - - if(vessel.targetObject!=null && vessel.targetObject.GetVessel()!=null) - { - targetVessel = vessel.targetObject.GetVessel(); - } - else if(parentVessel!=null && parentVessel.targetObject!=null && parentVessel.targetObject.GetVessel()!=null) - { - targetVessel = parentVessel.targetObject.GetVessel(); - } - else - { - return; - } - - if(!hasFired && targetVessel!=null) - { - hasFired = true; - guidanceActive = true; - vessel.OnFlyByWire += GuidanceSteer; - vessel.SetReferenceTransform(part); - GameObject velocityObject = new GameObject("velObject"); - velocityObject.transform.position = transform.position; - velocityObject.transform.parent = transform; - velocityTransform = velocityObject.transform; - - Events["StartGuidance"].guiActive = false; - Misc.RefreshAssociatedWindows(part); - - vessel.OnJustAboutToBeDestroyed += RemoveGuidance; - part.OnJustAboutToBeDestroyed += RemoveGuidance; - } - } - - - - - [KSPEvent(guiActive = true, guiActiveEditor = true, guiName = "GuidanceMode", active = true)] - public void SwitchGuidanceMode() - { - guidanceMode++; - if(guidanceMode > 3) - { - guidanceMode = 1; - } - - RefreshGuidanceMode(); - } - - void RefreshGuidanceMode() - { - switch(guidanceMode) - { - case 1: - guidanceLabel = "AAM"; - break; - case 2: - guidanceLabel = "AGM/STS"; - break; - case 3: - guidanceLabel = "Cruise"; - break; - } - - Fields["cruiseAltitude"].guiActive = (guidanceMode == 3); - Fields["cruiseAltitude"].guiActiveEditor = (guidanceMode == 3); - - - Misc.RefreshAssociatedWindows(part); - } - - - public override void OnStart (PartModule.StartState state) - { - part.force_activate(); - vesselTransform = part.FindModelTransform("vesselTransform"); - if(vesselTransform!=null) - { - part.SetReferenceTransform(vesselTransform); - } - parentVessel = vessel; - - RefreshGuidanceMode(); - - } - - void RemoveGuidance() - { - vessel.OnFlyByWire -= GuidanceSteer; - } - - public void GuidanceSteer(FlightCtrlState s) - { - if(guidanceActive && targetVessel!=null && vessel!=null && vesselTransform!=null && velocityTransform!=null) - { - velocityTransform.rotation = Quaternion.LookRotation(vessel.srf_velocity, -vesselTransform.forward); - Vector3 targetPosition = targetVessel.CoM; - Vector3 localAngVel = vessel.angularVelocity; - - if(guidanceMode == 1) - { - targetPosition = MissileGuidance.GetAirToAirTarget(targetPosition, vessel.srf_velocity, vessel.acceleration, vessel, out timeToImpact); - } - else if(guidanceMode == 2) - { - targetPosition = MissileGuidance.GetAirToGroundTarget(targetPosition, vessel, 1.85f); - } - else - { - targetPosition = MissileGuidance.GetCruiseTarget(targetPosition, vessel, cruiseAltitude); - } - - Vector3 targetDirection = velocityTransform.InverseTransformPoint(targetPosition).normalized; - targetDirection = Vector3.RotateTowards(Vector3.forward, targetDirection, 15*Mathf.Deg2Rad, 0); - - - - float steerYaw = (steerMult * targetDirection.x) - (steerDamping * -localAngVel.z); - float steerPitch = (steerMult * targetDirection.y) - (steerDamping * -localAngVel.x); - - s.yaw = Mathf.Clamp(steerYaw, -maxSteer, maxSteer); - s.pitch = Mathf.Clamp(steerPitch, -maxSteer, maxSteer); - - s.mainThrottle = 1; - } - } - } -} - diff --git a/BahaTurret/BDModulePilotAI.cs b/BahaTurret/BDModulePilotAI.cs deleted file mode 100644 index 785c0a659..000000000 --- a/BahaTurret/BDModulePilotAI.cs +++ /dev/null @@ -1,2121 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class BDModulePilotAI : PartModule - { - public enum SteerModes{NormalFlight, Aiming} - SteerModes steerMode = SteerModes.NormalFlight; - - public enum PilotCommands{Free, Attack, Follow, FlyTo} - - - [KSPField(isPersistant = true)] - public bool pilotEnabled = false; - - bool belowMinAltitude = false; - bool extending = false; - - bool requestedExtend = false; - Vector3 requestedExtendTpos; - - public bool IsExtending - { - get { return extending || requestedExtend; } - } - - public bool isLeadingFormation = false; - - public void RequestExtend(Vector3 tPosition) - { - requestedExtend = true; - requestedExtendTpos = tPosition; - } - - GameObject vobj; - Transform velocityTransform - { - get - { - if(!vobj) - { - vobj = new GameObject("velObject"); - vobj.transform.position = vessel.ReferenceTransform.position; - vobj.transform.parent = vessel.ReferenceTransform; - } - - return vobj.transform; - } - } - - - Vessel targetVessel; - - - Transform vesselTransform; - - Vector3 upDirection = Vector3.up; - - public MissileFire weaponManager; - - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Default Alt."), - UI_FloatRange(minValue = 500f, maxValue = 8500f, stepIncrement = 25f, scene = UI_Scene.All)] - public float defaultAltitude = 1500; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Min Altitude"), - UI_FloatRange(minValue = 150f, maxValue = 1500, stepIncrement = 10f, scene = UI_Scene.All)] - public float minAltitude = 500f; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Steer Factor"), - UI_FloatRange(minValue = 0.1f, maxValue = 20f, stepIncrement = .1f, scene = UI_Scene.All)] - public float steerMult = 6; - //make a combat steer mult and idle steer mult - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Pitch Ki"), - UI_FloatRange(minValue = 0f, maxValue = 20f, stepIncrement = .1f, scene = UI_Scene.All)] - public float pitchKiAdjust = 5; - - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Steer Limiter"), - UI_FloatRange(minValue = .1f, maxValue = 1f, stepIncrement = .05f, scene = UI_Scene.All)] - public float maxSteer = 1; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Steer Damping"), - UI_FloatRange(minValue = 1f, maxValue = 8f, stepIncrement = 0.5f, scene = UI_Scene.All)] - public float steerDamping = 3; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Max Speed"), - UI_FloatRange(minValue = 125f, maxValue = 800f, stepIncrement = 1.0f, scene = UI_Scene.All)] - public float maxSpeed = 325; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "TakeOff Speed"), - UI_FloatRange(minValue = 20f, maxValue = 200f, stepIncrement = 1.0f, scene = UI_Scene.All)] - public float takeOffSpeed = 70; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "MinCombatSpeed"), - UI_FloatRange(minValue = 20f, maxValue = 120, stepIncrement = 1.0f, scene = UI_Scene.All)] - public float minSpeed = 60f; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Idle Speed"), - UI_FloatRange(minValue = 20f, maxValue = 200f, stepIncrement = 1.0f, scene = UI_Scene.All)] - public float idleSpeed = 120f; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Max G"), - UI_FloatRange(minValue = 2f, maxValue = 25f, stepIncrement = 0.25f, scene = UI_Scene.All)] - public float maxAllowedGForce = 10; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Max AoA"), - UI_FloatRange(minValue = 0f, maxValue = 85f, stepIncrement = 2.5f, scene = UI_Scene.All)] - public float maxAllowedAoA = 35; - float maxAllowedCosAoA = 0; - float lastAllowedAoA = 0; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Standby Mode"), - UI_Toggle(enabledText = "On", disabledText = "Off")] - public bool standbyMode = false; - - //manueuverability and g loading data - float maxDynPresGRecorded = 0; - - float maxPosG = 0; - float cosAoAAtMaxPosG = 0; - - float maxNegG = 0; - float cosAoAAtMaxNegG = 0; - - float[] gLoadMovingAvgArray = new float[32]; - float[] cosAoAMovingAvgArray = new float[32]; - int movingAvgIndex = 0; - - float gLoadMovingAvg = 0; - float cosAoAMovingAvg = 0; - - float gaoASlopePerDynPres = 0; //used to limit control input at very high dynamic pressures to avoid structural failure - float gOffsetPerDynPres = 0; - - float posPitchDynPresLimitIntegrator = 1; - float negPitchDynPresLimitIntegrator = -1; - - float lastCosAoA = 0; - float lastPitchInput = 0; - - //Controller Integral - float pitchIntegral = 0; - - //instantaneous turn radius and possible acceleration from lift - //properties can be used so that other AI modules can read this for future maneuverability comparisons between craft - float turnRadius; - public float TurnRadius - { - get { return turnRadius; } - private set { turnRadius = value; } - } - - float maxLiftAcceleration; - public float MaxLiftAcceleration - { - get { return maxLiftAcceleration; } - private set { maxLiftAcceleration = value; } - } - - - float turningTimer = 0; - float evasiveTimer = 0; - Vector3 lastTargetPosition; - - string debugString = string.Empty; - - LineRenderer lr; - Vector3 flyingToPosition; - - public Vector3d defaultOrbitCoords; - - //speed controller - BDAirspeedControl speedController; - bool useAB = true; - bool useBrakes = true; - bool regainEnergy = false; - - //collision detection - int collisionDetectionTicker = 0; - float collisionDetectionTimer = 0; - Vector3 collisionAvoidDirection; - - //wing command - int commandFollowIndex = 0; - PilotCommands command; - public PilotCommands currentCommand - { - get - { - return command; - } - } - public ModuleWingCommander commandLeader; - bool useRollHint = false; - Vector3d commandGeoPos; - public Vector3d commandPosition - { - get - { - return VectorUtils.GetWorldSurfacePostion(commandGeoPos, vessel.mainBody); - } - set - { - commandGeoPos = VectorUtils.WorldPositionToGeoCoords(value, vessel.mainBody); - } - } - public Vector3d commandGPS - { - get - { - return commandGeoPos; - } - } - double commandSpeed; - Vector3d commandHeading; - public string currentStatus = "Free"; - - - void Start() - { - if(HighLogic.LoadedSceneIsFlight) - { - part.OnJustAboutToBeDestroyed += DeactivatePilot; - vessel.OnJustAboutToBeDestroyed += DeactivatePilot; - MissileFire.OnToggleTeam += OnToggleTeam; - vesselTransform = vessel.ReferenceTransform; - - foreach(var wm in vessel.FindPartModulesImplementing()) - { - weaponManager = wm; - break; - } - - if(pilotEnabled) - { - ActivatePilot(); - } - maxAllowedCosAoA = (float)Math.Cos(maxAllowedAoA * Math.PI / 180.0); - lastAllowedAoA = maxAllowedAoA; - } - - RefreshPartWindow(); - } - - void OnDestroy() - { - MissileFire.OnToggleTeam -= OnToggleTeam; - } - - void OnToggleTeam(MissileFire mf, BDArmorySettings.BDATeams team) - { - if(mf.vessel == vessel || (commandLeader && commandLeader.vessel == mf.vessel)) - { - ReleaseCommand(); - } - } - - [KSPAction("Activate Pilot")] - public void AGActivatePilot(KSPActionParam param) - { - ActivatePilot(); - } - - [KSPAction("Deactivate Pilot")] - public void AGDeactivatePilot(KSPActionParam param) - { - DeactivatePilot(); - } - - [KSPAction("Toggle Pilot")] - public void AGTogglePilot(KSPActionParam param) - { - TogglePilot(); - } - - - public void ActivatePilot() - { - pilotEnabled = true; - vessel.OnFlyByWire -= AutoPilot; - vessel.OnFlyByWire += AutoPilot; - belowMinAltitude = vessel.LandedOrSplashed; - - prevTargetDir = vesselTransform.up; - - if(!speedController) - { - speedController = gameObject.AddComponent(); - speedController.vessel = vessel; - } - - speedController.Activate(); - - GameEvents.onVesselDestroy.Remove(RemoveAutopilot); - GameEvents.onVesselDestroy.Add(RemoveAutopilot); - - defaultOrbitCoords = VectorUtils.WorldPositionToGeoCoords(vessel.ReferenceTransform.position, vessel.mainBody); - - RefreshPartWindow(); - } - - public void DeactivatePilot() - { - pilotEnabled = false; - vessel.OnFlyByWire -= AutoPilot; - RefreshPartWindow(); - - if(speedController) - { - speedController.Deactivate(); - } - } - - void RemoveAutopilot(Vessel v) - { - if(v == vessel) - { - v.OnFlyByWire -= AutoPilot; - } - } - - - - [KSPEvent(guiActive = true, guiName = "Toggle Pilot", active = true)] - public void TogglePilot() - { - if(pilotEnabled) - { - DeactivatePilot(); - } - else - { - ActivatePilot(); - } - } - - void RefreshPartWindow() - { - Events["TogglePilot"].guiName = pilotEnabled ? "Deactivate Pilot" : "Activate Pilot"; - - //Misc.RefreshAssociatedWindows(part); - } - - void Update() - { - if(BDArmorySettings.DRAW_DEBUG_LINES && pilotEnabled) - { - if(lr) - { - lr.enabled = true; - lr.SetPosition(0, vessel.ReferenceTransform.position); - lr.SetPosition(1, flyingToPosition); - } - else - { - lr = gameObject.AddComponent(); - lr.SetVertexCount(2); - lr.SetWidth(0.5f, 0.5f); - } - - - minSpeed = Mathf.Clamp(minSpeed, 0, idleSpeed - 20); - minSpeed = Mathf.Clamp(minSpeed, 0, maxSpeed - 20); - } - else - { - if(lr) - { - lr.enabled = false; - } - } - } - - - - float finalMaxSteer = 1; - void AutoPilot(FlightCtrlState s) - { - if(!vessel || !vessel.transform || vessel.packed || !vessel.mainBody) - { - return; - } - vesselTransform = vessel.ReferenceTransform; - finalMaxSteer = maxSteer; - - //default brakes off full throttle - //s.mainThrottle = 1; - - //vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, false); - AdjustThrottle(maxSpeed, true); - useAB = true; - useBrakes = true; - vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, true); - - steerMode = SteerModes.NormalFlight; - useVelRollTarget = false; - - - - GetGuardTarget(); - if(vessel.LandedOrSplashed && standbyMode && weaponManager && (BDATargetManager.TargetDatabase[BDATargetManager.BoolToTeam(weaponManager.team)].Count == 0||BDArmorySettings.PEACE_MODE)) - { - //s.mainThrottle = 0; - //vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true); - AdjustThrottle(0, true); - return; - } - //upDirection = -FlightGlobals.getGeeForceAtPosition(transform.position).normalized; - upDirection = VectorUtils.GetUpDirection(vessel.transform.position); - debugString = string.Empty; - - CalculateAccelerationAndTurningCircle(); - float minAltNeeded = MinAltitudeNeeded(); - debugString += "minAltNeeded: " + minAltNeeded; - if (MissileGuidance.GetRadarAltitude(vessel) < minAltNeeded) - { - belowMinAltitude = true; - } - - if(vessel.srfSpeed < minSpeed) - { - regainEnergy = true; - } - else if(!belowMinAltitude && vessel.srfSpeed > Mathf.Min(minSpeed + 20f, idleSpeed)) - { - regainEnergy = false; - } - - - - if (belowMinAltitude) - { - if(command != PilotCommands.Follow) - { - currentStatus = "Gain Alt."; - } - TakeOff(s); - turningTimer = 0; - } - else - { - if(FlyAvoidCollision(s)) - { - turningTimer = 0; - } - else if(command != PilotCommands.Free) - { - UpdateCommand(s); - } - else - { - UpdateAI(s); - } - } - UpdateGAndAoALimits(s); - AdjustPitchForGAndAoALimits(s); - - } - - void UpdateAI(FlightCtrlState s) - { - currentStatus = "Free"; - if(weaponManager && weaponManager.guardMode && !targetVessel) - { - TargetInfo potentialTarget = BDATargetManager.GetLeastEngagedTarget(weaponManager); - if(potentialTarget && potentialTarget.Vessel) - { - targetVessel = potentialTarget.Vessel; - } - } - - if(requestedExtend) - { - requestedExtend = false; - extending = true; - lastTargetPosition = requestedExtendTpos; - } - - if(evasiveTimer > 0 || (weaponManager && (weaponManager.missileIsIncoming || weaponManager.isChaffing || weaponManager.isFlaring || weaponManager.underFire))) - { - if(evasiveTimer < 1) - { - threatRelativePosition = vessel.srf_velocity.normalized + vesselTransform.right; - - if(weaponManager) - { - if(weaponManager.rwr.rwrEnabled) //use rwr to check missile threat direction - { - Vector3 missileThreat = Vector3.zero; - bool missileThreatDetected = false; - float closestMissileThreat = float.MaxValue; - for(int i = 0; i < weaponManager.rwr.pingsData.Length; i++) - { - TargetSignatureData threat = weaponManager.rwr.pingsData[i]; - if(threat.exists && threat.signalStrength == 4) - { - missileThreatDetected = true; - float dist = Vector3.Distance(weaponManager.rwr.pingWorldPositions[i], vesselTransform.position); - if(dist < closestMissileThreat) - { - closestMissileThreat = dist; - missileThreat = weaponManager.rwr.pingWorldPositions[i]; - } - } - } - if(missileThreatDetected) - { - threatRelativePosition = missileThreat - vesselTransform.position; - } - } - - if(weaponManager.underFire) - { - threatRelativePosition = weaponManager.incomingThreatPosition - vesselTransform.position; - } - } - } - Evasive(s); - evasiveTimer += Time.fixedDeltaTime; - turningTimer = 0; - - if(evasiveTimer > 3) - { - evasiveTimer = 0; - collisionDetectionTicker = 21; //check for collision again after exiting evasion routine - } - } - else if(!extending && weaponManager && targetVessel != null && targetVessel.transform != null) - { - evasiveTimer = 0; - if(!targetVessel.LandedOrSplashed) - { - Vector3 targetVesselRelPos = targetVessel.vesselTransform.position - vesselTransform.position; - if (vessel.altitude < defaultAltitude && Vector3.Angle(targetVesselRelPos, -upDirection) < 35) - { - //dangerous if low altitude and target is far below you - don't dive into ground! - extending = true; - lastTargetPosition = targetVessel.vesselTransform.position; - } - - if (Vector3.Angle(targetVessel.vesselTransform.position - vesselTransform.position, vesselTransform.up) > 35) - { - turningTimer += Time.deltaTime; - } - else - { - turningTimer = 0; - } - - debugString += "\nturningTimer: " + turningTimer; - - float targetForwardDot = Vector3.Dot(targetVesselRelPos.normalized, vesselTransform.up); - float targetVelFrac = (float)(targetVessel.srfSpeed / vessel.srfSpeed); //this is the ratio of the target vessel's velocity to this vessel's srfSpeed in the forward direction; this allows smart decisions about when to break off the attack - - if (targetVelFrac < 0.8f && targetForwardDot < 0.2f && targetVesselRelPos.magnitude < 400) - { - extending = true; - lastTargetPosition = targetVessel.vesselTransform.position - vessel.srf_velocity; //we'll set our last target pos based on the enemy vessel and where we were 1 seconds ago - weaponManager.ForceScan(); - } - if(turningTimer > 15) - { - //extend if turning circles for too long - //extending = true; - RequestExtend(targetVessel.vesselTransform.position); - turningTimer = 0; - weaponManager.ForceScan(); - //lastTargetPosition = targetVessel.transform.position; - } - } - else //extend if too close for agm attack - { - float extendDistance = Mathf.Clamp(weaponManager.guardRange - 1800, 2500, 4000); - float srfDist = Vector3.Distance(GetSurfacePosition(targetVessel.transform.position), GetSurfacePosition(vessel.transform.position)); - - if(srfDist < extendDistance && Vector3.Angle(vesselTransform.up, targetVessel.transform.position - vessel.transform.position) > 45) - { - extending = true; - lastTargetPosition = targetVessel.transform.position; - weaponManager.ForceScan(); - } - } - - - if(!extending) - { - currentStatus = "Engaging"; - debugString += "\nFlying to target"; - FlyToTargetVessel(s, targetVessel); - } - } - else - { - evasiveTimer = 0; - if(!extending) - { - currentStatus = "Orbiting"; - FlyOrbit(s, defaultOrbitCoords, 2000, idleSpeed, true); - } - } - - if(extending) - { - evasiveTimer = 0; - currentStatus = "Extending"; - debugString += "\nExtending"; - FlyExtend(s, lastTargetPosition); - } - } - - - bool FlyAvoidCollision(FlightCtrlState s) - { - if(collisionDetectionTimer > 2) - { - collisionDetectionTimer = 0; - collisionDetectionTicker = 20; - } - if(collisionDetectionTimer > 0) - { - //fly avoid - currentStatus = "AvoidCollision"; - debugString += "\nAvoiding Collision"; - collisionDetectionTimer += Time.fixedDeltaTime; - - - Vector3 target = vesselTransform.position + collisionAvoidDirection; - FlyToPosition(s, target); - return true; - } - else if(collisionDetectionTicker > 20) - { - collisionDetectionTicker = 0; - bool avoid = false; - Vector3 badDirection; - if(DetectCollision(flyingToPosition - vesselTransform.position, out badDirection)) - { - avoid = true; - } - else if(command != PilotCommands.Follow && !isLeadingFormation) //check collisions with other flying vessels - { - foreach(var v in BDATargetManager.LoadedVessels) - { - if(v && v!=vessel && !v.Landed && Vector3.Dot(v.transform.position-vesselTransform.position, vesselTransform.up) > 0) - { - if(PredictCollisionWithVessel(v, 2.5f, 0.5f, out badDirection)) - { - avoid = true; - break; - } - } - } - } - - if(avoid) - { - collisionDetectionTimer += Time.fixedDeltaTime; - Vector3 axis = -Vector3.Cross(vesselTransform.up, badDirection); - collisionAvoidDirection = Quaternion.AngleAxis(25, axis) * badDirection; //don't need to change the angle that much to avoid, and it should prevent stupid suicidal manuevers as well - - FlyAvoidCollision(s); - return true; - } - } - else - { - collisionDetectionTicker++; - } - - return false; - } - - bool PredictCollisionWithVessel(Vessel v, float maxTime, float interval, out Vector3 badDirection) - { - if(v == weaponManager.incomingMissileVessel) //evasive will handle avoiding missiles - { - badDirection = Vector3.zero; - return false; - } - - float time = Mathf.Min(0.5f, maxTime); - while(time < maxTime) - { - Vector3 tPos = PredictPosition(v, time); - Vector3 myPos = PredictPosition(vessel, time); - if(Vector3.SqrMagnitude(tPos - myPos) < 900f) - { - badDirection = tPos - vesselTransform.position; - return true; - } - - time = Mathf.MoveTowards(time, maxTime, interval); - } - - badDirection = Vector3.zero; - return false; - } - - Vector3 PredictPosition(Vessel v, float time) - { - Vector3 pos = v.CoM; - pos += v.srf_velocity * time; - pos += 0.5f * v.acceleration * time * time; - return pos; - } - - void FlyToTargetVessel(FlightCtrlState s, Vessel v) - { - Vector3 target = v.CoM; - MissileLauncher missile = null; - Vector3 vectorToTarget = v.transform.position - vesselTransform.position; - float distanceToTarget = vectorToTarget.magnitude; - float planarDistanceToTarget = Vector3.ProjectOnPlane(vectorToTarget, upDirection).magnitude; - float angleToTarget = Vector3.Angle(target - vesselTransform.position, vesselTransform.up); - if(weaponManager) - { - missile = weaponManager.currentMissile; - if(missile != null) - { - if(missile.GetWeaponClass() == WeaponClasses.Missile) - { - if(distanceToTarget > 5500f) - { - finalMaxSteer = GetSteerLimiterForSpeedAndPower(); - } - - if(missile.targetingMode == MissileLauncher.TargetingModes.Heat && !weaponManager.heatTarget.exists) - { - debugString += "\nAttempting heat lock"; - target += v.srf_velocity.normalized * 10; - } - else - { - target = MissileGuidance.GetAirToAirFireSolution(missile, v); - } - - if(angleToTarget < 20f) - { - steerMode = SteerModes.Aiming; - } - } - else //bombing - { - if(distanceToTarget > 4500f) - { - finalMaxSteer = GetSteerLimiterForSpeedAndPower(); - } - - if(angleToTarget < 45f) - { - /* - target = GetSurfacePosition(target) + (vessel.upAxis * vessel.altitude); - Vector3 fixedTDir = Quaternion.FromToRotation(Vector3.ProjectOnPlane(vessel.srf_velocity, vessel.upAxis), target - vesselTransform.position) * (target - vesselTransform.position); - target = FlightPosition(vesselTransform.position + fixedTDir, Mathf.Max(defaultAltitude - 500f, minAltitude)); - */ - - target = target + (Mathf.Max(defaultAltitude - 500f, minAltitude) * upDirection); - Vector3 tDir = (target - vesselTransform.position).normalized; - tDir = (1000 * tDir) - (vessel.srf_velocity.normalized * 600); - target = vesselTransform.position + tDir; - - } - else - { - target = target + (Mathf.Max(defaultAltitude - 500f, minAltitude) * upDirection); - } - } - } - else if(weaponManager.currentGun) - { - ModuleWeapon weapon = weaponManager.currentGun; - if(weapon != null) - { - Vector3 leadOffset = weapon.GetLeadOffset(); - - float targetAngVel = Vector3.Angle(v.transform.position - vessel.transform.position, v.transform.position + (vessel.srf_velocity) - vessel.transform.position); - debugString += "\ntargetAngVel: " + targetAngVel; - float magnifier = Mathf.Clamp(targetAngVel, 1f, 2f); - magnifier += ((magnifier-1f) * Mathf.Sin(Time.time *0.75f)); - target -= magnifier * leadOffset; - - angleToTarget = Vector3.Angle(vesselTransform.up, target - vesselTransform.position); - if(distanceToTarget < weaponManager.gunRange && angleToTarget < 20) - { - steerMode = SteerModes.Aiming; //steer to aim - } - else - { - if(distanceToTarget > 3500f || vessel.srfSpeed < takeOffSpeed) - { - finalMaxSteer = GetSteerLimiterForSpeedAndPower(); - } - else - { - //figuring how much to lead the target's movement to get there after its movement assuming we can manage a constant speed turn - //this only runs if we're not aiming and not that far from the target - float curVesselMaxAccel = Math.Min(maxDynPresGRecorded * (float)vessel.dynamicPressurekPa, maxAllowedGForce * 9.81f); - if (curVesselMaxAccel > 0) - { - float timeToTurn = (float)vessel.srfSpeed * angleToTarget * Mathf.Deg2Rad / curVesselMaxAccel; - target += v.srf_velocity * timeToTurn; - //target += 0.5f * v.acceleration * timeToTurn * timeToTurn; - } - } - } - - if(v.LandedOrSplashed) - { - if(distanceToTarget > defaultAltitude * 2.2f) - { - target = FlightPosition(target, defaultAltitude); - } - else - { - steerMode = SteerModes.Aiming; - } - } - else if(distanceToTarget > weaponManager.gunRange * 1.5f || Vector3.Dot(target - vesselTransform.position, vesselTransform.up) < 0) - { - target = v.CoM; - } - } - } - else if(planarDistanceToTarget > weaponManager.gunRange * 1.25f && (vessel.altitude < targetVessel.altitude || MissileGuidance.GetRadarAltitude(vessel) < defaultAltitude)) //climb to target vessel's altitude if lower and still too far for guns - { - finalMaxSteer = GetSteerLimiterForSpeedAndPower(); - target = vesselTransform.position + GetLimitedClimbDirectionForSpeed(vectorToTarget); - } - else - { - finalMaxSteer = GetSteerLimiterForSpeedAndPower(); - } - } - - - float targetDot = Vector3.Dot(vesselTransform.up, v.transform.position-vessel.transform.position); - - //manage speed when close to enemy - float finalMaxSpeed = maxSpeed; - if(targetDot > 0) - { - finalMaxSpeed = Mathf.Max((distanceToTarget - 100) / 8, 0) + (float)v.srfSpeed; - finalMaxSpeed = Mathf.Max(finalMaxSpeed, minSpeed+25f); - } - AdjustThrottle(finalMaxSpeed, true); - - if((targetDot < 0 && vessel.srfSpeed > finalMaxSpeed) - && distanceToTarget < 300 && vessel.srfSpeed < v.srfSpeed * 1.25f && Vector3.Dot(vessel.srf_velocity, v.srf_velocity) > 0) //distance is less than 800m - { - debugString += ("\nEnemy on tail. Braking"); - AdjustThrottle(minSpeed, true); - } - if(missile!=null - && targetDot > 0 - && distanceToTarget < MissileLaunchParams.GetDynamicLaunchParams(missile, v.srf_velocity, v.transform.position).minLaunchRange - && vessel.srfSpeed > idleSpeed) - { - //extending = true; - //lastTargetPosition = v.transform.position; - RequestExtend(lastTargetPosition); - } - - if(regainEnergy && angleToTarget > 30f) - { - RegainEnergy(s, target - vesselTransform.position); - return; - } - else - { - useVelRollTarget = true; - FlyToPosition(s, target); - return; - } - } - - - - void RegainEnergy(FlightCtrlState s, Vector3 direction) - { - debugString += "\nRegaining energy"; - steerMode = SteerModes.Aiming; - Vector3 planarDirection = Vector3.ProjectOnPlane(direction, upDirection); - float angle = (Mathf.Clamp(MissileGuidance.GetRadarAltitude(vessel) - minAltitude, 0, 1500) / 1500) * 90; - angle = Mathf.Clamp(angle, 0, 55) * Mathf.Deg2Rad; - Vector3 targetDirection = Vector3.RotateTowards(planarDirection, -upDirection, angle, 0); - targetDirection = Vector3.RotateTowards(vessel.srf_velocity, targetDirection, 15f * Mathf.Deg2Rad, 0).normalized; - - AdjustThrottle(maxSpeed, false); - FlyToPosition(s, vesselTransform.position + (targetDirection*100)); - } - - float GetSteerLimiterForSpeedAndPower() - { - float possibleAccel = speedController.GetPossibleAccel(); - float speed = (float)vessel.srfSpeed; - debugString += "\npossibleAccel: " + possibleAccel; - float limiter = ((speed-50) / 330f) + possibleAccel / 15f; - debugString += "\nunclamped limiter: " + limiter; - return Mathf.Clamp01(limiter); - } - - //test - Vector3 prevTargetDir; - bool useVelRollTarget = false; - void FlyToPosition(FlightCtrlState s, Vector3 targetPosition) - { - if(!belowMinAltitude) - { - if(weaponManager && Time.time - weaponManager.timeBombReleased < 1.5f) - { - targetPosition = vessel.transform.position + vessel.srf_velocity; - } - - targetPosition = FlightPosition(targetPosition, minAltitude); - targetPosition = vesselTransform.position + ((targetPosition - vesselTransform.position).normalized * 100); - } - - Vector3d srfVel = vessel.srf_velocity; - if(srfVel != Vector3d.zero) - { - velocityTransform.rotation = Quaternion.LookRotation(srfVel, -vesselTransform.forward); - } - velocityTransform.rotation = Quaternion.AngleAxis(90, velocityTransform.right) * velocityTransform.rotation; - - //ang vel - Vector3 localAngVel = vessel.angularVelocity; - //test - Vector3 currTargetDir = (targetPosition-vesselTransform.position).normalized; - if(steerMode == SteerModes.NormalFlight) - { - float gRotVel = ((10f * maxAllowedGForce) / ((float)vessel.srfSpeed)); - //currTargetDir = Vector3.RotateTowards(prevTargetDir, currTargetDir, gRotVel*Mathf.Deg2Rad, 0); - } - Vector3 targetAngVel = Vector3.Cross(prevTargetDir, currTargetDir)/Time.fixedDeltaTime; - Vector3 localTargetAngVel = vesselTransform.InverseTransformVector(targetAngVel); - prevTargetDir = currTargetDir; - targetPosition = vessel.transform.position + (currTargetDir * 100); - - - if(BDArmorySettings.DRAW_DEBUG_LINES) - { - flyingToPosition = targetPosition; - } - - //test poststall - float AoA = Vector3.Angle(vessel.ReferenceTransform.up, vessel.srf_velocity); - if(AoA > 30f) - { - steerMode = SteerModes.Aiming; - } - - //slow down for tighter turns - float velAngleToTarget = Vector3.Angle(targetPosition-vesselTransform.position, vessel.srf_velocity); - float normVelAngleToTarget = Mathf.Clamp(velAngleToTarget, 0, 90)/90; - float speedReductionFactor = 1.25f; - float finalSpeed = Mathf.Min(speedController.targetSpeed, Mathf.Clamp(maxSpeed - (speedReductionFactor * normVelAngleToTarget), idleSpeed, maxSpeed)); - debugString += "\nFinal Target Speed: " + finalSpeed.ToString("0.0"); - AdjustThrottle(finalSpeed, useBrakes, useAB); - - - - if(steerMode == SteerModes.Aiming) - { - localAngVel -= localTargetAngVel; - } - - Vector3 targetDirection; - Vector3 targetDirectionYaw; - float yawError; - float pitchError; - //float postYawFactor; - //float postPitchFactor; - if(steerMode == SteerModes.NormalFlight) - { - targetDirection = velocityTransform.InverseTransformDirection(targetPosition - velocityTransform.position).normalized; - targetDirection = Vector3.RotateTowards(Vector3.up, targetDirection, 45 * Mathf.Deg2Rad, 0); - - targetDirectionYaw = vesselTransform.InverseTransformDirection(vessel.srf_velocity).normalized; - targetDirectionYaw = Vector3.RotateTowards(Vector3.up, targetDirectionYaw, 45 * Mathf.Deg2Rad, 0); - - - //postYawFactor = 0.25f; - //postPitchFactor = 0.8f; - } - else//(steerMode == SteerModes.Aiming) - { - targetDirection = vesselTransform.InverseTransformDirection(targetPosition-vesselTransform.position).normalized; - targetDirection = Vector3.RotateTowards(Vector3.up, targetDirection, 25 * Mathf.Deg2Rad, 0); - targetDirectionYaw = targetDirection; - - /* - if(command == PilotCommands.Follow) - { - postYawFactor = 0.45f; - postPitchFactor = 1f; - } - else - { - postYawFactor = 1f; - postPitchFactor = 1.2f; - } - */ - } - - pitchError = VectorUtils.SignedAngle(Vector3.up, Vector3.ProjectOnPlane(targetDirection, Vector3.right), Vector3.back); - yawError = VectorUtils.SignedAngle(Vector3.up, Vector3.ProjectOnPlane(targetDirectionYaw, Vector3.forward), Vector3.right); - - - - - //test - debugString += "\n finalMaxSteer: " + finalMaxSteer; - - - - - - - - //roll - Vector3 currentRoll = -vesselTransform.forward; - float rollUp = (steerMode == SteerModes.Aiming ? 5f : 10f); - if(steerMode == SteerModes.NormalFlight) - { - rollUp += (1 - finalMaxSteer) * 10f; - } - rollTarget = (targetPosition + (rollUp * upDirection)) - vesselTransform.position; - - //test - if(steerMode == SteerModes.Aiming && !belowMinAltitude) - { - angVelRollTarget = -140 * vesselTransform.TransformVector(Quaternion.AngleAxis(90f, Vector3.up) * localTargetAngVel); - rollTarget += angVelRollTarget; - } - - if(command == PilotCommands.Follow && useRollHint) - { - rollTarget = -commandLeader.vessel.ReferenceTransform.forward; - } - - // - if(belowMinAltitude) - { - rollTarget = vessel.upAxis * 100; - - } - if(useVelRollTarget && !belowMinAltitude) - { - rollTarget = Vector3.ProjectOnPlane(rollTarget, vessel.srf_velocity); - currentRoll = Vector3.ProjectOnPlane(currentRoll, vessel.srf_velocity); - } - else - { - rollTarget = Vector3.ProjectOnPlane(rollTarget, vesselTransform.up); - } - - //v/q - float dynamicAdjustment = Mathf.Clamp(16*(float)(vessel.srfSpeed/vessel.dynamicPressurekPa), 0, 1.2f); - - float rollError = Misc.SignedAngle(currentRoll, rollTarget, vesselTransform.right); - float steerRoll = (steerMult * 0.0015f * rollError); - float rollDamping = (.10f * steerDamping * -localAngVel.y); - steerRoll -= rollDamping; - steerRoll *= dynamicAdjustment; - - if(steerMode == SteerModes.NormalFlight) - { - //premature dive fix - pitchError = pitchError * Mathf.Clamp01((21 - Mathf.Exp(Mathf.Abs(rollError) / 30)) / 20); - } - - float steerPitch = (0.015f * steerMult * pitchError) - (steerDamping * -localAngVel.x); - float steerYaw = (0.005f * steerMult * yawError) - (steerDamping * 0.2f * -localAngVel.z); - - pitchIntegral += pitchError; - - steerPitch *= dynamicAdjustment; - steerYaw *= dynamicAdjustment; - - float pitchKi = 0.1f * (pitchKiAdjust/5); //This is what should be allowed to be tweaked by the player, just like the steerMult, it is very low right now - pitchIntegral = Mathf.Clamp(pitchIntegral, -0.2f / (pitchKi * dynamicAdjustment), 0.2f / (pitchKi * dynamicAdjustment)); //0.2f is the limit of the integral variable, making it bigger increases overshoot - steerPitch += pitchIntegral * pitchKi * dynamicAdjustment; //Adds the integral component to the mix - - float roll = Mathf.Clamp(steerRoll, -maxSteer, maxSteer); - s.roll = roll; - s.yaw = Mathf.Clamp(steerYaw, -finalMaxSteer, finalMaxSteer); - s.pitch = Mathf.Clamp(steerPitch, Mathf.Min(-finalMaxSteer, -0.2f), finalMaxSteer); - } - - Vector3 rollTarget; - Vector3 angVelRollTarget; - - - void FlyExtend(FlightCtrlState s, Vector3 tPosition) - { - if(weaponManager) - { - if (weaponManager.TargetOverride) - { - extending = false; - weaponManager.ForceWideViewScan(); - } - else - weaponManager.ForceWideViewScan(); - - - float extendDistance = Mathf.Clamp(weaponManager.guardRange-1800, 2500, 4000); - - if(weaponManager.currentMissile && weaponManager.currentMissile.GetWeaponClass() == WeaponClasses.Bomb) - { - extendDistance = 4500; - } - - if(targetVessel!=null && !targetVessel.LandedOrSplashed) //this is just asking for trouble at 800m - { - extendDistance = 1600; - } - - Vector3 srfVector = Vector3.ProjectOnPlane(vessel.transform.position - tPosition, upDirection); - float srfDist = srfVector.magnitude; - if(srfDist < extendDistance) - { - Vector3 targetDirection = srfVector.normalized*extendDistance; - Vector3 target = vessel.transform.position + targetDirection; - target = GetTerrainSurfacePosition(target) + (vessel.upAxis*Mathf.Min(defaultAltitude, MissileGuidance.GetRaycastRadarAltitude(vesselTransform.position))); - target = FlightPosition(target, defaultAltitude); - if(regainEnergy) - { - RegainEnergy(s, target - vesselTransform.position); - return; - } - else - { - FlyToPosition(s, target); - } - } - else - { - extending = false; - } - } - else - { - extending = false; - } - } - - void FlyOrbit(FlightCtrlState s, Vector3d centerGPS, float radius, float speed, bool clockwise) - { - if(regainEnergy) - { - RegainEnergy(s, vessel.srf_velocity); - return; - } - - finalMaxSteer = GetSteerLimiterForSpeedAndPower(); - - debugString += "\nFlying orbit"; - Vector3 flightCenter = GetTerrainSurfacePosition(VectorUtils.GetWorldSurfacePostion(centerGPS, vessel.mainBody)) + (defaultAltitude*upDirection); - - - Vector3 myVectorFromCenter = Vector3.ProjectOnPlane(vessel.transform.position - flightCenter, upDirection); - Vector3 myVectorOnOrbit = myVectorFromCenter.normalized * radius; - - Vector3 targetVectorFromCenter = Quaternion.AngleAxis(clockwise ? 15f : -15f, upDirection) * myVectorOnOrbit; - - Vector3 verticalVelVector = Vector3.Project(vessel.srf_velocity, upDirection); //for vv damping - - Vector3 targetPosition = flightCenter + targetVectorFromCenter - (verticalVelVector * 0.25f); - - Vector3 vectorToTarget = targetPosition - vesselTransform.position; - //Vector3 planarVel = Vector3.ProjectOnPlane(vessel.srf_velocity, upDirection); - //vectorToTarget = Vector3.RotateTowards(planarVel, vectorToTarget, 25f * Mathf.Deg2Rad, 0); - vectorToTarget = GetLimitedClimbDirectionForSpeed(vectorToTarget); - targetPosition = vesselTransform.position + vectorToTarget; - - if(command != PilotCommands.Free && Vector3.Distance(vessel.transform.position, flightCenter) < radius*1.5f) - { - Debug.Log("AI Pilot reached command destination."); - command = PilotCommands.Free; - } - - useVelRollTarget = true; - - AdjustThrottle(speed, false); - FlyToPosition(s, targetPosition); - } - - //sends target speed to speedController - void AdjustThrottle(float targetSpeed, bool useBrakes, bool allowAfterburner = true) - { - speedController.targetSpeed = targetSpeed; - speedController.useBrakes = useBrakes; - speedController.allowAfterburner = allowAfterburner; - } - - Vector3 threatRelativePosition; - void Evasive(FlightCtrlState s) - { - currentStatus = "Evading"; - debugString += "\nEvasive"; - debugString += "\n Threat Distance: " + weaponManager.incomingMissileDistance; - - collisionDetectionTicker += 2; - - - if(weaponManager) - { - if(weaponManager.isFlaring) - { - useAB = vessel.srfSpeed < minSpeed; - useBrakes = false; - float targetSpeed = minSpeed; - if(weaponManager.isChaffing) - { - targetSpeed = maxSpeed; - } - AdjustThrottle(targetSpeed, false, useAB); - } - - - if((weaponManager.isChaffing || weaponManager.isFlaring) && (weaponManager.incomingMissileDistance > 2000)) - { - debugString += "\nBreaking from missile threat!"; - Vector3 axis = -Vector3.Cross(vesselTransform.up, threatRelativePosition); - Vector3 breakDirection = Quaternion.AngleAxis(90, axis) * threatRelativePosition; - //Vector3 breakTarget = vesselTransform.position + breakDirection; - RegainEnergy(s, breakDirection); - return; - } - else if(weaponManager.underFire) - { - debugString += "\nDodging gunfire"; - float threatDirectionFactor = Vector3.Dot(vesselTransform.up, threatRelativePosition.normalized); - //Vector3 axis = -Vector3.Cross(vesselTransform.up, threatRelativePosition); - - Vector3 breakTarget = threatRelativePosition * 2f; //for the most part, we want to turn _towards_ the threat in order to increase the rel ang vel and get under its guns - - if (threatDirectionFactor > 0.9f) //within 28 degrees in front - { - breakTarget += Vector3.Cross(threatRelativePosition.normalized, Mathf.Sign(Mathf.Sin((float)vessel.missionTime / 2)) * vessel.upAxis); - debugString += " from directly ahead!"; - } - else if (threatDirectionFactor < -0.9) //within ~28 degrees behind - { - float threatDistance = threatRelativePosition.magnitude; - if(threatDistance > 400) - { - breakTarget = vesselTransform.position + vesselTransform.up * 1500 - 500 * vessel.upAxis; - breakTarget += Mathf.Sin((float)vessel.missionTime / 2) * vesselTransform.right * 1000 - Mathf.Cos((float)vessel.missionTime / 2) * vesselTransform.forward * 1000; - if(threatDistance > 800) - debugString += " from behind afar; engaging barrel roll"; - else - { - debugString += " from behind moderate distance; engaging aggressvie barrel roll and braking"; - steerMode = SteerModes.Aiming; - AdjustThrottle(minSpeed, true, false); - } - } - else - { - breakTarget = threatRelativePosition; - if (evasiveTimer < 1.5f) - breakTarget += Mathf.Sin((float)vessel.missionTime * 2) * vesselTransform.right * 500; - else - breakTarget += -Math.Sign(Mathf.Sin((float)vessel.missionTime * 2)) * vesselTransform.right * 150; - debugString += " from directly behind and close; breaking hard"; - steerMode = SteerModes.Aiming; - } - } - else - { - float threatDistance = threatRelativePosition.magnitude; - if(threatDistance < 400) - { - breakTarget += Mathf.Sin((float)vessel.missionTime * 2) * vesselTransform.right * 100; - debugString += " from the side; breaking in"; - steerMode = SteerModes.Aiming; - } - else - { - breakTarget = vesselTransform.position + vesselTransform.up * 1500; - breakTarget += Mathf.Sin((float)vessel.missionTime / 2) * vesselTransform.right * 1000 - Mathf.Cos((float)vessel.missionTime / 2) * vesselTransform.forward * 1000; - debugString += " from far side; engaging barrel roll"; - } - } - - float threatAltitudeDiff = Vector3.Dot(threatRelativePosition, vessel.upAxis); - if (threatAltitudeDiff > 500) - breakTarget += threatAltitudeDiff * vessel.upAxis; //if it's trying to spike us from below, don't go crazy trying to dive below it - else - breakTarget += - 150 * vessel.upAxis; //dive a bit to escape - - FlyToPosition(s, breakTarget); - return; - - } - else if(weaponManager.incomingMissileVessel) - { - float mSqrDist = Vector3.SqrMagnitude(weaponManager.incomingMissileVessel.transform.position - vesselTransform.position); - if(mSqrDist < 810000) //900m - { - debugString += "\nMissile about to impact! pull away!"; - AdjustThrottle(maxSpeed, false, false); - Vector3 cross = Vector3.Cross(weaponManager.incomingMissileVessel.transform.position - vesselTransform.position, vessel.srf_velocity).normalized; - if(Vector3.Dot(cross, -vesselTransform.forward) < 0) - { - cross = -cross; - } - FlyToPosition(s, vesselTransform.position +(50*vessel.srf_velocity/vessel.srfSpeed)+ (100 * cross)); - return; - } - - - - } - } - - Vector3 target = (vessel.srfSpeed < 200) ? FlightPosition(vessel.transform.position, minAltitude) : vesselTransform.position; - float angleOff = Mathf.Sin(Time.time * 0.75f) * 180; - angleOff = Mathf.Clamp(angleOff, -45, 45); - target += - (Quaternion.AngleAxis(angleOff, upDirection) * Vector3.ProjectOnPlane(vesselTransform.up * 500, upDirection)); - //+ (Mathf.Sin (Time.time/3) * upDirection * minAltitude/3); - - - FlyToPosition(s, target); - } - - void TakeOff(FlightCtrlState s) - { - debugString += "\nTaking off/Gaining altitude"; - - if(vessel.LandedOrSplashed && vessel.srfSpeed < takeOffSpeed) - { - defaultOrbitCoords = VectorUtils.WorldPositionToGeoCoords(vessel.transform.position, vessel.mainBody); - return; - } - - steerMode = SteerModes.Aiming; - - float radarAlt = MissileGuidance.GetRadarAltitude(vessel); - - Vector3 forwardPoint = vessel.transform.position + Vector3.ProjectOnPlane(vesselTransform.up * 100, upDirection); - float terrainDiff = MissileGuidance.GetRaycastRadarAltitude(forwardPoint) - radarAlt; - terrainDiff = Mathf.Max(terrainDiff, 0); - - float rise = Mathf.Clamp((float)vessel.srfSpeed * 0.3f, 5, 100); - - if(radarAlt > 70) - { - vessel.ActionGroups.SetGroup(KSPActionGroup.Gear, false); - } - else - { - vessel.ActionGroups.SetGroup(KSPActionGroup.Gear, true); - } - - FlyToPosition(s, forwardPoint + (upDirection * (rise+terrainDiff))); - - if(radarAlt > minAltitude) - { - belowMinAltitude = false; - } - } - - Vector3 GetLimitedClimbDirectionForSpeed(Vector3 direction) - { - if(Vector3.Dot(direction, upDirection) < 0) - { - debugString += "\nclimb limit angle: unlimited"; - return direction; //only use this if climbing - } - - Vector3 planarDirection = Vector3.ProjectOnPlane(direction, upDirection).normalized * 100; - - float angle = Mathf.Clamp((float)vessel.srfSpeed * 0.13f, 5, 90); - - debugString += "\nclimb limit angle: " + angle.ToString("0.0"); - return Vector3.RotateTowards(planarDirection, direction, angle*Mathf.Deg2Rad, 0); - } - - void UpdateGAndAoALimits(FlightCtrlState s) - { - if (vessel.dynamicPressurekPa <= 0 || vessel.srfSpeed < takeOffSpeed || belowMinAltitude && -Vector3.Dot(vessel.ReferenceTransform.forward, vessel.upAxis) < 0.8f) - { - return; - } - - if(lastAllowedAoA != maxAllowedAoA) - { - lastAllowedAoA = maxAllowedAoA; - maxAllowedCosAoA = (float)Math.Cos(lastAllowedAoA * Math.PI / 180.0); - } - float pitchG = -Vector3.Dot(vessel.acceleration, vessel.ReferenceTransform.forward); //should provide g force in vessel up / down direction, assuming a standard plane - float pitchGPerDynPres = pitchG / (float)vessel.dynamicPressurekPa; - - float curCosAoA = Vector3.Dot(vessel.srf_velocity.normalized, vessel.ReferenceTransform.forward); - - //adjust moving averages - //adjust gLoad average - gLoadMovingAvg *= 32f; - gLoadMovingAvg -= gLoadMovingAvgArray[movingAvgIndex]; - gLoadMovingAvgArray[movingAvgIndex] = pitchGPerDynPres; - gLoadMovingAvg += pitchGPerDynPres; - gLoadMovingAvg /= 32f; - - //adjusting cosAoAAvg - cosAoAMovingAvg *= 32f; - cosAoAMovingAvg -= cosAoAMovingAvgArray[movingAvgIndex]; - cosAoAMovingAvgArray[movingAvgIndex] = curCosAoA; - cosAoAMovingAvg += curCosAoA; - cosAoAMovingAvg /= 32f; - - ++movingAvgIndex; - if (movingAvgIndex == gLoadMovingAvgArray.Length) - movingAvgIndex = 0; - - if (gLoadMovingAvg < maxNegG || Math.Abs(cosAoAMovingAvg - cosAoAAtMaxNegG) < 0.005f) - { - maxNegG = gLoadMovingAvg; - cosAoAAtMaxNegG = cosAoAMovingAvg; - } - if (gLoadMovingAvg > maxPosG || Math.Abs(cosAoAMovingAvg - cosAoAAtMaxPosG) < 0.005f) - { - maxPosG = gLoadMovingAvg; - cosAoAAtMaxPosG = cosAoAMovingAvg; - } - - if(cosAoAAtMaxNegG >= cosAoAAtMaxPosG) - { - cosAoAAtMaxNegG = cosAoAAtMaxPosG = maxNegG = maxPosG = 0; - gOffsetPerDynPres = gaoASlopePerDynPres = 0; - return; - } - - if (maxPosG > maxDynPresGRecorded) - maxDynPresGRecorded = maxPosG; - - float aoADiff = cosAoAAtMaxPosG - cosAoAAtMaxNegG; - - //if (Math.Abs(pitchControlDiff) < 0.005f) - // return; //if the pitch control values are too similar, don't bother to avoid numerical errors - - - gaoASlopePerDynPres = (maxPosG - maxNegG) / aoADiff; - gOffsetPerDynPres = maxPosG - gaoASlopePerDynPres * cosAoAAtMaxPosG; //g force offset - } - - void AdjustPitchForGAndAoALimits(FlightCtrlState s) - { - float minCosAoA, maxCosAoA; - //debugString += "\nMax Pos G: " + maxPosG + " @ " + cosAoAAtMaxPosG; - //debugString += "\nMax Neg G: " + maxNegG + " @ " + cosAoAAtMaxNegG; - - if (vessel.LandedOrSplashed || vessel.srfSpeed < Math.Min(minSpeed, takeOffSpeed)) //if we're going too slow, don't use this - { - float speed = Math.Max(takeOffSpeed, minSpeed); - negPitchDynPresLimitIntegrator = -1f * 0.001f * 0.5f * 1.225f * speed * speed; - posPitchDynPresLimitIntegrator = 1f * 0.001f * 0.5f * 1.225f * speed * speed; - return; - } - - float invVesselDynPreskPa = 1f / (float)vessel.dynamicPressurekPa; - - maxCosAoA = maxAllowedGForce * 9.81f * invVesselDynPreskPa; - minCosAoA = -maxCosAoA; - - maxCosAoA -= gOffsetPerDynPres; - minCosAoA -= gOffsetPerDynPres; - - maxCosAoA /= gaoASlopePerDynPres; - minCosAoA /= gaoASlopePerDynPres; - - if (maxCosAoA > maxAllowedCosAoA) - maxCosAoA = maxAllowedCosAoA; - - if (minCosAoA < -maxAllowedCosAoA) - minCosAoA = -maxAllowedCosAoA; - - float curCosAoA = Vector3.Dot(vessel.srf_velocity / vessel.srfSpeed, vessel.ReferenceTransform.forward); - - - float centerCosAoA = (minCosAoA + maxCosAoA) * 0.5f; - float curCosAoACentered = curCosAoA - centerCosAoA; - float cosAoADiff = 0.5f * Math.Abs(maxCosAoA - minCosAoA); - float curCosAoANorm = curCosAoACentered / cosAoADiff; //scaled so that from centerAoA to maxAoA is 1 - - - float negPitchScalar, posPitchScalar; - negPitchScalar = negPitchDynPresLimitIntegrator * invVesselDynPreskPa - lastPitchInput; - posPitchScalar = lastPitchInput - posPitchDynPresLimitIntegrator * invVesselDynPreskPa; - - //update pitch control limits as needed - float negPitchDynPresLimit, posPitchDynPresLimit; - negPitchDynPresLimit = posPitchDynPresLimit = 0; - if (curCosAoANorm < -0.15f)// || Math.Abs(negPitchScalar) < 0.01f) - { - float cosAoAOffset = curCosAoANorm + 1; //set max neg aoa to be 0 - float aoALimScalar = Math.Abs(curCosAoANorm); - aoALimScalar *= aoALimScalar; - aoALimScalar *= aoALimScalar; - aoALimScalar *= aoALimScalar; - if (aoALimScalar > 1) - aoALimScalar = 1; - - float pitchInputScalar = negPitchScalar; - pitchInputScalar = 1 - Mathf.Clamp01(Math.Abs(pitchInputScalar)); - pitchInputScalar *= pitchInputScalar; - pitchInputScalar *= pitchInputScalar; - pitchInputScalar *= pitchInputScalar; - if (pitchInputScalar < 0) - pitchInputScalar = 0; - - float deltaCosAoANorm = curCosAoA - lastCosAoA; - deltaCosAoANorm /= cosAoADiff; - - debugString += "\nUpdating Neg Gs"; - negPitchDynPresLimitIntegrator -= 0.01f * Mathf.Clamp01(aoALimScalar + pitchInputScalar) * cosAoAOffset * (float)vessel.dynamicPressurekPa; - negPitchDynPresLimitIntegrator -= 0.005f * deltaCosAoANorm * (float)vessel.dynamicPressurekPa; - if (cosAoAOffset < 0) - negPitchDynPresLimit = -0.3f * cosAoAOffset; - } - if (curCosAoANorm > 0.15f)// || Math.Abs(posPitchScalar) < 0.01f) - { - float cosAoAOffset = curCosAoANorm - 1; //set max pos aoa to be 0 - float aoALimScalar = Math.Abs(curCosAoANorm); - aoALimScalar *= aoALimScalar; - aoALimScalar *= aoALimScalar; - aoALimScalar *= aoALimScalar; - if (aoALimScalar > 1) - aoALimScalar = 1; - - float pitchInputScalar = posPitchScalar; - pitchInputScalar = 1 - Mathf.Clamp01(Math.Abs(pitchInputScalar)); - pitchInputScalar *= pitchInputScalar; - pitchInputScalar *= pitchInputScalar; - pitchInputScalar *= pitchInputScalar; - if (pitchInputScalar < 0) - pitchInputScalar = 0; - - float deltaCosAoANorm = curCosAoA - lastCosAoA; - deltaCosAoANorm /= cosAoADiff; - - debugString += "\nUpdating Pos Gs"; - posPitchDynPresLimitIntegrator -= 0.01f * Mathf.Clamp01(aoALimScalar + pitchInputScalar) * cosAoAOffset * (float)vessel.dynamicPressurekPa; - posPitchDynPresLimitIntegrator -= 0.005f * deltaCosAoANorm * (float)vessel.dynamicPressurekPa; - if(cosAoAOffset > 0) - posPitchDynPresLimit = -0.3f * cosAoAOffset; - } - - float currentG = -Vector3.Dot(vessel.acceleration, vessel.ReferenceTransform.forward); - float negLim, posLim; - negLim = negPitchDynPresLimitIntegrator * invVesselDynPreskPa + negPitchDynPresLimit; - if (negLim > s.pitch) - { - if (currentG > -(maxAllowedGForce * 0.97f * 9.81f)) - { - negPitchDynPresLimitIntegrator -= (float)(0.15 * vessel.dynamicPressurekPa); //jsut an override in case things break - - maxNegG = currentG * invVesselDynPreskPa; - cosAoAAtMaxNegG = curCosAoA; - - negPitchDynPresLimit = 0; - - //maxPosG = 0; - //cosAoAAtMaxPosG = 0; - } - - s.pitch = negLim; - debugString += "\nLimiting Neg Gs"; - } - posLim = posPitchDynPresLimitIntegrator * invVesselDynPreskPa + posPitchDynPresLimit; - if (posLim < s.pitch) - { - if (currentG < (maxAllowedGForce * 0.97f * 9.81f)) - { - posPitchDynPresLimitIntegrator += (float)(0.15 * vessel.dynamicPressurekPa); //jsut an override in case things break - - maxPosG = currentG * invVesselDynPreskPa; - cosAoAAtMaxPosG = curCosAoA; - - posPitchDynPresLimit = 0; - - //maxNegG = 0; - //cosAoAAtMaxNegG = 0; - } - - s.pitch = posLim; - debugString += "\nLimiting Pos Gs"; - } - - lastPitchInput = s.pitch; - lastCosAoA = curCosAoA; - debugString += "\nNeg Pitch Lim: " + negLim; - debugString += "\nPos Pitch Lim: " + posLim; - - } - - void CalculateAccelerationAndTurningCircle() - { - maxLiftAcceleration = maxDynPresGRecorded; - maxLiftAcceleration *= (float)vessel.dynamicPressurekPa; //maximum acceleration from lift that the vehicle can provide - - maxLiftAcceleration = Math.Min(maxLiftAcceleration, maxAllowedGForce * 9.81f); //limit it to whichever is smaller, what we can provide or what we can handle - maxLiftAcceleration = maxAllowedGForce * 9.81f; - - if(maxLiftAcceleration > 0) - turnRadius = (float)vessel.srf_velocity.sqrMagnitude / maxLiftAcceleration; //radius that we can turn in assuming constant velocity, assuming simple circular motion - } - - float MinAltitudeNeeded() //min altitude adjusted for G limits; let's try _not_ to overcook dives and faceplant into the ground - { - //for a pure vertical dive, turnRadius will be the altitude that we need to turn. However, for shallower dives we don't need that much. Let's account for that. - //actual altitude needed will be radius * (1 - cos(theta)), where theta is the angle of the arc from dive entry to the turning circle to the bottom - //we can calculate that from the velocity vector mag dotted with the up vector - - float diveAngleCorrection = -Vector3.Dot(vessel.srf_velocity / vessel.srfSpeed, vessel.upAxis); //normalize the vector and dot it with upAxis - //this gives us sin(theta) - if(diveAngleCorrection > 0) //we're headed downwards - { - diveAngleCorrection *= diveAngleCorrection; - diveAngleCorrection = 1 - diveAngleCorrection; - diveAngleCorrection = Math.Max(0f, diveAngleCorrection); //remember to check to make sure numerical errors haven't crept in! Can't have NaN showing up - diveAngleCorrection = Mathf.Sqrt(diveAngleCorrection); //convert sin(theta) to cos(theta) - - diveAngleCorrection = 1 - diveAngleCorrection; //and convert to 1 - cos(theta) - } - else - { - diveAngleCorrection = 0; - } - - return Math.Max(minAltitude, 100 + turnRadius * diveAngleCorrection); - } - - Vector3 DefaultAltPosition() - { - return (vessel.transform.position + (-(float)vessel.altitude*upDirection) + (defaultAltitude *upDirection)); - } - - Vector3 GetSurfacePosition(Vector3 position) - { - return position - ((float)FlightGlobals.getAltitudeAtPos(position) * upDirection); - } - - Vector3 GetTerrainSurfacePosition(Vector3 position) - { - return position - (MissileGuidance.GetRaycastRadarAltitude(position) * upDirection); - } - - - Vector3 FlightPosition(Vector3 targetPosition, float minAlt) - { - Vector3 forwardDirection = vesselTransform.up; - Vector3 targetDirection = (targetPosition - vesselTransform.position).normalized; - - float vertFactor = 0; - vertFactor += (((float)vessel.srfSpeed / minSpeed) - 2f) * 0.3f; //speeds greater than 2x minSpeed encourage going upwards; below encourages downwards - vertFactor += (((targetPosition - vesselTransform.position).magnitude / 1000f) - 1f) * 0.3f; //distances greater than 1000m encourage going upwards; closer encourages going downwards - vertFactor -= Mathf.Clamp01(Vector3.Dot(vesselTransform.position - targetPosition, upDirection) / 1600f - 1f) * 0.5f; //being higher than 1600m above a target encourages going downwards - if (targetVessel) - vertFactor += Vector3.Dot(targetVessel.srf_velocity / targetVessel.srfSpeed, (targetVessel.ReferenceTransform.position - vesselTransform.position).normalized) * 0.3f; //the target moving away from us encourages upward motion, moving towards us encourages downward motion - else - vertFactor += 0.4f; - vertFactor -= weaponManager.underFire ? 0.5f : 0; //being under fire encourages going downwards as well, to gain energy - - float alt = MissileGuidance.GetRadarAltitude(vessel); - - if (vertFactor > 2) - vertFactor = 2; - if (vertFactor < -2) - vertFactor = -2; - - /*if ((weaponManager.TargetOverride && vessel.srfSpeed > minSpeed * 3) || - (!weaponManager.TargetOverride && (vessel.srfSpeed > minSpeed * 1.5f)) && - Vector3.Dot(targetPosition-vesselTransform.position, upDirection) > -1000 && ( - ((targetPosition - vesselTransform.position).magnitude > 1200 || targetVessel == null || vessel.srfSpeed > targetVessel.srfSpeed * 1.5f) || - (Vector3.Dot(forwardDirection, upDirection) > 0.4f && Vector3.Dot(vesselTransform.forward, targetDirection) < 0)) && - !weaponManager.underFire) //go upwards in some way - { - vertFactor = (float)vessel.srfSpeed / (minSpeed * 1.5f); - --vertFactor; - vertFactor *= 0.8f; - vertFactor = Mathf.Clamp01(vertFactor); - } - else if(alt > minAltitude) - { - vertFactor = (alt - minAltitude) / (2 * turnRadius); - vertFactor = Mathf.Clamp01(vertFactor); - vertFactor = -vertFactor; - }*/ - - vertFactor += 0.15f * Mathf.Sin((float)vessel.missionTime * 0.25f); //some randomness in there - - Vector3 projectedDirection = Vector3.ProjectOnPlane(forwardDirection, upDirection); - Vector3 projectedTargetDirection = Vector3.ProjectOnPlane(targetDirection, upDirection); - if(Vector3.Dot(targetDirection, forwardDirection) < 0) - { - if(Vector3.Angle(projectedTargetDirection, projectedDirection) > 165f) - { - targetPosition = vesselTransform.position + (Quaternion.AngleAxis(Mathf.Sign(Mathf.Sin((float)vessel.missionTime / 4)) * 45, upDirection) * (projectedDirection.normalized * 200)); - targetDirection = (targetPosition - vesselTransform.position).normalized; - } - - targetPosition = vesselTransform.position + Vector3.RotateTowards(projectedDirection, Vector3.ProjectOnPlane(targetDirection, upDirection) + upDirection * vertFactor, 45*Mathf.Deg2Rad, 0).normalized*200; - } - else if(steerMode != SteerModes.Aiming) - { - float distance = (targetPosition - vesselTransform.position).magnitude; - if (vertFactor < 0) - distance = Math.Min(distance, Math.Abs((alt - minAlt) / vertFactor)); - - targetPosition += upDirection * Math.Min(distance, 1000) * vertFactor * (1 - Math.Abs(Vector3.Dot(projectedTargetDirection, projectedDirection))); - /*if (vertFactor < 0) - targetPosition += upDirection * Math.Min((alt - minAltitude), (targetPosition - vesselTransform.position).magnitude) * 0.2f * vertFactor * (1 - Math.Abs(Vector3.Dot(projectedTargetDirection, projectedDirection))); - else - { - if(targetVessel) - vertFactor *= (1f + Mathf.Clamp((float)(vessel.srfSpeed - targetVessel.srfSpeed), 0, float.PositiveInfinity) * 0.05f); - if (Vector3.Dot(targetPosition - vesselTransform.position, upDirection) > 0) - targetPosition += upDirection * Vector3.Dot(targetPosition - vesselTransform.position, upDirection) * vertFactor * (1 - Math.Abs(Vector3.Dot(projectedTargetDirection, projectedDirection))); - else - targetPosition += upDirection * (targetPosition - vesselTransform.position).magnitude * vertFactor * (1 - Math.Abs(Vector3.Dot(projectedTargetDirection, projectedDirection))); - }*/ - } - - - if(MissileGuidance.GetRadarAltitude(vessel) > minAlt * 1.1f) - { - return targetPosition; - } - - float pointRadarAlt = MissileGuidance.GetRaycastRadarAltitude(targetPosition); - if(pointRadarAlt < minAlt) - { - float adjustment = (minAlt-pointRadarAlt); - debugString += "\nTarget position is below minAlt. Adjusting by "+adjustment; - return targetPosition + (adjustment * upDirection); - } - else - { - return targetPosition; - } - } - - public bool GetLaunchAuthorization(Vessel targetV, MissileFire mf) - { - bool launchAuthorized = false; - Vector3 target = targetV.transform.position; - MissileLauncher missile = mf.currentMissile; - if(missile != null) - { - if(!targetV.LandedOrSplashed) - { - target = MissileGuidance.GetAirToAirFireSolution(missile, targetV); - } - - float boresightFactor = targetV.LandedOrSplashed ? 0.75f : 0.35f; - float maxOffBoresight = missile.maxOffBoresight; - if(missile.targetingMode == MissileLauncher.TargetingModes.GPS) maxOffBoresight = 45; - - float fTime = 2f; - Vector3 futurePos = target + (targetV.srf_velocity * fTime); - Vector3 myFuturePos = vesselTransform.position + (vessel.srf_velocity * fTime); - bool fDot = Vector3.Dot(vesselTransform.up, futurePos - myFuturePos) > 0; //check target won't likely be behind me soon - - if(fDot && Vector3.Angle(missile.missileReferenceTransform.forward, target - missile.transform.position) < maxOffBoresight * boresightFactor) - { - launchAuthorized = true; - } - } - - return launchAuthorized; - } - - void GetGuardTarget() - { - if(weaponManager!=null && weaponManager.vessel == vessel) - { - if(weaponManager.guardMode && weaponManager.currentTarget!=null) - { - targetVessel = weaponManager.currentTarget.Vessel; - } - else - { - targetVessel = null; - } - weaponManager.pilotAI = this; - return; - } - else - { - foreach(var mf in vessel.FindPartModulesImplementing()) - { - if(mf.currentTarget!=null) - { - targetVessel = mf.currentTarget.Vessel; - } - else - { - targetVessel = null; - } - - weaponManager = mf; - mf.pilotAI = this; - - return; - } - } - } - - bool DetectCollision(Vector3 direction, out Vector3 badDirection) - { - badDirection = Vector3.zero; - if(MissileGuidance.GetRadarAltitude(vessel) < 20) return false; - - direction = direction.normalized; - int layerMask = 1<<15; - Ray ray = new Ray(vesselTransform.position + (50*vesselTransform.up), direction); - float distance = Mathf.Clamp((float)vessel.srfSpeed * 4f, 125f, 2500); - RaycastHit hit; - if(Physics.SphereCast(ray, 10, out hit, distance, layerMask)) - { - Rigidbody otherRb = hit.collider.attachedRigidbody; - if(otherRb) - { - if(Vector3.Dot(otherRb.velocity, vessel.srf_velocity) < 0) - { - badDirection = hit.point - ray.origin; - return true; - } - else - { - return false; - } - } - else - { - badDirection = hit.point - ray.origin; - return true; - } - } - else - { - return false; - } - } - - void UpdateCommand(FlightCtrlState s) - { - if(command == PilotCommands.Follow && !commandLeader) - { - ReleaseCommand(); - return; - } - - if(command == PilotCommands.Follow) - { - currentStatus = "Follow"; - UpdateFollowCommand(s); - } - else if(command == PilotCommands.FlyTo) - { - currentStatus = "Fly To"; - FlyOrbit(s, defaultOrbitCoords, 2500, idleSpeed, true); - } - else if(command == PilotCommands.Attack) - { - currentStatus = "Attack"; - FlyOrbit(s, defaultOrbitCoords, 4500, maxSpeed, true); - } - } - - void UpdateFollowCommand(FlightCtrlState s) - { - steerMode = SteerModes.NormalFlight; - vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, false); - - commandSpeed = commandLeader.vessel.srfSpeed; - commandHeading = commandLeader.vessel.srf_velocity.normalized; - - //formation position - commandPosition = GetFormationPosition(); - - float distanceToPos = Vector3.Distance(vesselTransform.position, commandPosition); - - - - float dotToPos = Vector3.Dot(vesselTransform.up, commandPosition - vesselTransform.position); - Vector3 flyPos; - useRollHint = false; - - float ctrlModeThresh = 1000; - - if(distanceToPos < ctrlModeThresh) - { - flyPos = commandPosition + (ctrlModeThresh * commandHeading); - - Vector3 vectorToFlyPos = flyPos - vessel.ReferenceTransform.position; - Vector3 projectedPosOffset = Vector3.ProjectOnPlane(commandPosition - vessel.ReferenceTransform.position, commandHeading); - float posOffsetMag = projectedPosOffset.magnitude; - float adjustAngle = (Mathf.Clamp(posOffsetMag * 0.27f, 0, 25)); - Vector3 projVel = Vector3.Project(vessel.srf_velocity - commandLeader.vessel.srf_velocity, projectedPosOffset); - adjustAngle -= Mathf.Clamp(Mathf.Sign(Vector3.Dot(projVel, projectedPosOffset)) * projVel.magnitude * 0.12f, -10, 10); - - adjustAngle *= Mathf.Deg2Rad; - - vectorToFlyPos = Vector3.RotateTowards(vectorToFlyPos, projectedPosOffset, adjustAngle, 0); - - flyPos = vessel.ReferenceTransform.position + vectorToFlyPos; - - if(distanceToPos < 400) - { - steerMode = SteerModes.Aiming; - } - else - { - steerMode = SteerModes.NormalFlight; - } - - if(distanceToPos < 10) - { - useRollHint = true; - } - } - else - { - steerMode = SteerModes.NormalFlight; - flyPos = commandPosition; - } - - double finalMaxSpeed = commandSpeed; - if(dotToPos > 0) - { - finalMaxSpeed += (distanceToPos / 8); - } - else - { - finalMaxSpeed -= (distanceToPos / 2); - } - - - AdjustThrottle((float)finalMaxSpeed, true); - - - FlyToPosition(s, flyPos); - } - - Vector3d GetFormationPosition() - { - Quaternion origVRot = velocityTransform.rotation; - Vector3 origVLPos = velocityTransform.localPosition; - - velocityTransform.position = commandLeader.vessel.ReferenceTransform.position; - if(commandLeader.vessel.srf_velocity != Vector3d.zero) - { - velocityTransform.rotation = Quaternion.LookRotation(commandLeader.vessel.srf_velocity, upDirection); - velocityTransform.rotation = Quaternion.AngleAxis(90, velocityTransform.right) * velocityTransform.rotation; - } - else - { - velocityTransform.rotation = commandLeader.vessel.ReferenceTransform.rotation; - } - - /* - Vector3 lateralVelVector = Vector3.Project(vessel.srf_velocity, velocityTransform.right)/2; - Vector3.ClampMagnitude(lateralVelVector, 25); - - Vector3 verticalVelVector = Vector3.Project(vessel.srf_velocity - commandLeader.vessel.srf_velocity, velocityTransform.forward) * 1;//0.75f; //MOVE THIS TO UpdateFollowCommand TO REGULATE VERTICAL POSITION AND SPEED - Vector3.ClampMagnitude(verticalVelVector, 25); - */ - - Vector3d pos = velocityTransform.TransformPoint(GetLocalFormationPosition(commandFollowIndex));// - lateralVelVector - verticalVelVector; - - velocityTransform.localPosition = origVLPos; - velocityTransform.rotation = origVRot; - - return pos; - } - - Vector3d GetLocalFormationPosition(int index) - { - float indexF = (float)index; - indexF++; - - double rightSign = indexF % 2 == 0 ? -1 : 1; - double positionFactor = Math.Ceiling(indexF/ 2); - double spread = commandLeader.spread; - double lag = commandLeader.lag; - - double right = rightSign * positionFactor * spread; - double back = positionFactor * lag * -1; - - return new Vector3d(right, back, 0); - } - - - public void ReleaseCommand() - { - if(vessel && command != PilotCommands.Free) - { - if(command == PilotCommands.Follow) - { - if(commandLeader) - { - foreach(var pilot in commandLeader.vessel.FindPartModulesImplementing()) - { - pilot.isLeadingFormation = false; - } - } - } - - Debug.Log(vessel.vesselName + " was released from command."); - command = PilotCommands.Free; - - defaultOrbitCoords = VectorUtils.WorldPositionToGeoCoords(vesselTransform.position, vessel.mainBody); - } - } - - public void CommandFollow(ModuleWingCommander leader, int followerIndex) - { - if(!pilotEnabled) - { - return; - } - - if(leader == vessel || followerIndex < 0) - { - return; - } - - Debug.Log(vessel.vesselName + " was commanded to follow."); - command = PilotCommands.Follow; - commandLeader = leader; - commandFollowIndex = followerIndex; - - foreach(var pilot in commandLeader.vessel.FindPartModulesImplementing()) - { - pilot.isLeadingFormation = true; - } - } - - public void CommandAG(KSPActionGroup ag) - { - if(!pilotEnabled) - { - return; - } - - - vessel.ActionGroups.ToggleGroup(ag); - } - - public void CommandFlyTo(Vector3 gpsCoords) - { - if(!pilotEnabled) - { - return; - } - - - Debug.Log(vessel.vesselName + " was commanded to fly to."); - defaultOrbitCoords = gpsCoords; - commandGeoPos = gpsCoords; - command = PilotCommands.FlyTo; - } - - public void CommandAttack(Vector3 gpsCoords) - { - if(!pilotEnabled) - { - return; - } - - - Debug.Log(vessel.vesselName + " was commanded to attack."); - defaultOrbitCoords = gpsCoords; - commandGeoPos = gpsCoords; - command = PilotCommands.Attack; - } - - void OnGUI() - { - if(pilotEnabled && vessel.isActiveVessel) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(200, Screen.height - 200, 400, 400), debugString); - } - - if(BDArmorySettings.DRAW_DEBUG_LINES) - { - if(command == PilotCommands.Follow) - { - BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, commandPosition, 2, Color.red); - } - - - BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position, vesselTransform.position + rollTarget, 2, Color.blue); - BDGUIUtils.DrawLineBetweenWorldPositions(vesselTransform.position + (0.05f * vesselTransform.right), vesselTransform.position + (0.05f * vesselTransform.right) + angVelRollTarget, 2, Color.green); - } - - - } - } - - } -} diff --git a/BahaTurret/BDRotaryRail.cs b/BahaTurret/BDRotaryRail.cs deleted file mode 100644 index 0d050b4d5..000000000 --- a/BahaTurret/BDRotaryRail.cs +++ /dev/null @@ -1,994 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class BDRotaryRail : PartModule - { - [KSPField] - public float maxLength; - - [KSPField] - public float maxHeight; - - [KSPField] - public int intervals; - - [KSPField] - public float rotationSpeed = 360; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Rails")] - public float numberOfRails = 8; - float railAngle = 0; - - [KSPField] - public float rotationDelay = 0.15f; - - [KSPField(isPersistant = true)] - public int railIndex = 0; - - - Dictionary missileToRailIndex; - Dictionary railToMissileIndex; - - [KSPField(isPersistant = true)] - public float currentHeight = 0; - - [KSPField(isPersistant = true)] - public float currentLength = 0; - - - public int missileCount = 0; - MissileLauncher[] missileChildren; - Transform[] missileTransforms; - Transform[] missileReferenceTransforms; - - Dictionary comOffsets; - - - float lengthInterval; - float heightInterval; - - List rotationTransforms; - List heightTransforms; - List lengthTransforms; - List rails; - int[] railCounts = new int[]{2,3,4,6,8}; - - [KSPField(isPersistant = true)] - public float railCountIndex = 4; - - bool rdyToFire = false; - public bool readyToFire - { - get - { - return rdyToFire; - } - } - - public MissileLauncher nextMissile = null; - - MissileLauncher rdyMissile = null; - public MissileLauncher readyMissile - { - get - { - return rdyMissile; - } - } - - MissileFire wm; - public MissileFire weaponManager - { - get - { - if(!wm || wm.vessel != vessel) - { - wm = null; - - foreach(var mf in vessel.FindPartModulesImplementing()) - { - wm = mf; - break; - } - } - - return wm; - } - } - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Rails++")] - public void RailsPlus() - { - IncreaseRails(true); - } - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Rails--")] - public void RailsMinus() - { - DecreaseRails(true); - } - - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Height++")] - public void HeightPlus() - { - IncreaseHeight(true); - } - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Height--")] - public void HeightMinus() - { - DecreaseHeight(true); - } - - public void IncreaseHeight(bool updateSym) - { - float prevHeight = currentHeight; - currentHeight = Mathf.Min(currentHeight + heightInterval, maxHeight); - - UpdateChildrenHeight(currentHeight - prevHeight); - UpdateModelState(); - - if(updateSym) - { - foreach(Part p in part.symmetryCounterparts) - { - if(p != part) - { - p.FindModuleImplementing().IncreaseHeight(false); - } - } - } - } - - public void DecreaseHeight(bool updateSym) - { - float prevHeight = currentHeight; - currentHeight = Mathf.Max(currentHeight - heightInterval, 0); - - UpdateChildrenHeight(currentHeight - prevHeight); - UpdateModelState(); - - if(updateSym) - { - foreach(Part p in part.symmetryCounterparts) - { - if(p != part) - { - p.FindModuleImplementing().DecreaseHeight(false); - } - } - } - } - - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Length++")] - public void LengthPlus() - { - IncreaseLength(true); - } - - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Length--")] - public void LengthMinus() - { - DecreaseLength(true); - } - - public void IncreaseLength(bool updateSym) - { - float prevLength = currentLength; - currentLength = Mathf.Min(currentLength + lengthInterval, maxLength); - - UpdateModelState(); - - MoveEndStackNode(currentLength - prevLength); - - UpdateChildrenLength(currentLength - prevLength); - - if(updateSym) - { - foreach(Part p in part.symmetryCounterparts) - { - if(p != part) - { - p.FindModuleImplementing().IncreaseLength(false); - } - } - } - } - - public void DecreaseLength(bool updateSym) - { - float prevLength = currentLength; - currentLength = Mathf.Max(currentLength - lengthInterval, 0); - - UpdateModelState(); - - MoveEndStackNode(currentLength - prevLength); - - UpdateChildrenLength(currentLength - prevLength); - - if(updateSym) - { - foreach(Part p in part.symmetryCounterparts) - { - if(p != part) - { - p.FindModuleImplementing().DecreaseLength(false); - } - } - } - } - - - - public void IncreaseRails(bool updateSym) - { - railCountIndex = Mathf.Min(railCountIndex + 1, railCounts.Length-1); - numberOfRails = railCounts[Mathf.RoundToInt(railCountIndex)]; - UpdateRails(Mathf.RoundToInt(numberOfRails)); - - if(updateSym) - { - foreach(Part p in part.symmetryCounterparts) - { - //p.FindModuleImplementing().IncreaseRails(false); - p.FindModuleImplementing().SetRailCount(Mathf.RoundToInt(numberOfRails), railCountIndex); - } - } - } - - public void SetRailCount(int railCount, float railCountIndex) - { - this.railCountIndex = railCountIndex; - numberOfRails = railCount; - UpdateRails(Mathf.RoundToInt(numberOfRails)); - } - - public void DecreaseRails(bool updateSym) - { - railCountIndex = Mathf.Max(railCountIndex - 1, 0); - numberOfRails = railCounts[Mathf.RoundToInt(railCountIndex)]; - UpdateRails(Mathf.RoundToInt(numberOfRails)); - - if(updateSym) - { - foreach(Part p in part.symmetryCounterparts) - { - //p.FindModuleImplementing().DecreaseRails(false); - p.FindModuleImplementing().SetRailCount(Mathf.RoundToInt(numberOfRails), railCountIndex); - } - } - } - - public void MoveEndStackNode(float offset) - { - foreach(var node in part.attachNodes) - { - if(node.nodeType == AttachNode.NodeType.Stack && node.id.ToLower().Contains("move")) - { - node.position += offset * Vector3.up; - } - } - } - - IEnumerator DelayedMoveStackNode(float offset) - { - yield return null; - MoveEndStackNode(offset); - } - - void UpdateRails(int railAmount) - { - if(rails.Count == 0) - { - rails.Add(part.FindModelTransform("railTransform")); - var extraRails = part.FindModelTransforms("newRail"); - for(int i = 0; i < extraRails.Length; i++) - { - rails.Add(extraRails[i]); - } - } - - for(int i = 1; i < rails.Count; i++) - { - foreach(var t in rails[i].GetComponentsInChildren()) - { - t.name = "deleted"; - } - Destroy(rails[i].gameObject); - } - - rails.RemoveRange(1, rails.Count - 1); - lengthTransforms.Clear(); - heightTransforms.Clear(); - rotationTransforms.Clear(); - - railAngle = 360f / (float)railAmount; - - for(int i = 1; i < railAmount; i++) - { - GameObject newRail = (GameObject)Instantiate(rails[0].gameObject); - newRail.name = "newRail"; - newRail.transform.parent = rails[0].parent; - newRail.transform.localPosition = rails[0].localPosition; - newRail.transform.localRotation = Quaternion.AngleAxis((float)i*railAngle, rails[0].parent.InverseTransformDirection(part.transform.up)) * rails[0].localRotation; - rails.Add(newRail.transform); - } - - foreach(var t in part.FindModelTransform("rotaryBombBay").GetComponentsInChildren()) - { - switch(t.name) - { - case "lengthTransform": - lengthTransforms.Add(t); - break; - case "heightTransform": - heightTransforms.Add(t); - break; - case "rotationTransform": - rotationTransforms.Add(t); - break; - } - } - } - - public override void OnStart(StartState state) - { - missileToRailIndex = new Dictionary(); - railToMissileIndex = new Dictionary(); - - lengthInterval = maxLength / intervals; - heightInterval = maxHeight / intervals; - - - numberOfRails = railCounts[Mathf.RoundToInt(railCountIndex)]; - - rails = new List(); - rotationTransforms = new List(); - heightTransforms = new List(); - lengthTransforms = new List(); - - UpdateModelState(); - - //MoveEndStackNode(currentLength); - if(HighLogic.LoadedSceneIsEditor) - { - StartCoroutine(DelayedMoveStackNode(currentLength)); - //part.AddOnMouseEnter(OnPartEnter); - //part.AddOnMouseExit(OnPartExit); - part.OnEditorAttach += OnAttach; - //previousSymMethod = EditorLogic.fetch.symmetryMethod; - - /* - foreach(var pSym in part.symmetryCounterparts) - { - var otherRail = pSym.FindModuleImplementing(); - if(otherRail.numberOfRails != numberOfRails) - { - SetRailCount(Mathf.RoundToInt(otherRail.numberOfRails), otherRail.railCountIndex); - break; - } - } - */ - } - - if(HighLogic.LoadedSceneIsFlight) - { - UpdateMissileChildren(); - - RotateToIndex(railIndex, true); - } - } - - void OnAttach() - { - UpdateRails(Mathf.RoundToInt(numberOfRails)); - } - - - - void UpdateChildrenHeight(float offset) - { - foreach(Part p in part.children) - { - //if(p.parent != part) continue; - - Vector3 direction = p.transform.position - part.transform.position; - direction = Vector3.ProjectOnPlane(direction, part.transform.up).normalized; - - p.transform.position += direction * offset; - } - } - - void UpdateChildrenLength(float offset) - { - bool parentInFront = Vector3.Dot(part.parent.transform.position-part.transform.position, part.transform.up) > 0; - if(parentInFront) - { - offset = -offset; - } - - Vector3 direction = part.transform.up; - - if(!parentInFront) - { - foreach(Part p in part.children) - { - if(p.FindModuleImplementing() && p.parent == part) continue; - - p.transform.position += direction * offset; - } - } - - if(parentInFront) - { - part.transform.position += direction * offset; - } - } - - void UpdateModelState() - { - UpdateRails(Mathf.RoundToInt(numberOfRails)); - - for(int i = 0; i < heightTransforms.Count; i++) - { - Vector3 lp = heightTransforms[i].localPosition; - heightTransforms[i].localPosition = new Vector3(lp.x, -currentHeight, lp.z); - } - - for(int i = 0; i < lengthTransforms.Count; i++) - { - Vector3 lp = lengthTransforms[i].localPosition; - lengthTransforms[i].localPosition = new Vector3(lp.x, lp.y, currentLength); - } - - // - } - - public void RotateToMissile(MissileLauncher ml) - { - if(missileCount == 0) return; - if(!ml) return; - - if(readyMissile == ml) return; - - //rotate to this missile specifically - for(int i = 0; i < missileChildren.Length; i++) - { - if(missileChildren[i] == ml) - { - RotateToIndex(missileToRailIndex[i], false); - nextMissile = ml; - return; - } - } - - //specific missile isnt here, but check if this type exists here - - if(readyMissile && readyMissile.part.name == ml.part.name) return; //current missile is correct type - - //look for missile type - for(int i = 0; i < missileChildren.Length; i++) - { - if(missileChildren[i].GetShortName() == ml.GetShortName()) - { - RotateToIndex(missileToRailIndex[i], false); - nextMissile = missileChildren[i]; - return; - } - } - } - - void UpdateIndexDictionary() - { - missileToRailIndex.Clear(); - railToMissileIndex.Clear(); - - for(int i = 0; i < missileCount; i++) - { - float closestSqr = float.MaxValue; - int rIndex = 0; - for(int r = 0; r < numberOfRails; r++) - { - Vector3 railPos = Quaternion.AngleAxis((float)r*railAngle, part.transform.up) * part.transform.forward; - railPos += part.transform.position; - float sqrDist = (missileChildren[i].transform.position - railPos).sqrMagnitude; - if(sqrDist < closestSqr) - { - rIndex = r; - closestSqr = sqrDist; - } - } - missileToRailIndex.Add(i, rIndex); - railToMissileIndex.Add(rIndex, i); - //Debug.Log("Adding to index dictionary: " + i + " : " + rIndex); - } - } - - - - void RotateToIndex(int index, bool instant) - { - //Debug.Log("Rotary rail is rotating to index: " + index); - - if(rotationRoutine != null) - { - StopCoroutine(rotationRoutine); - } - - // if(railIndex == index && readyToFire) return; - - if(missileCount > 0) - { - if(railToMissileIndex.ContainsKey(index)) - { - nextMissile = missileChildren[railToMissileIndex[index]]; - } - } - else - { - nextMissile = null; - } - - if(!nextMissile && missileCount > 0) - { - RotateToIndex(Mathf.RoundToInt(Mathf.Repeat(index + 1, numberOfRails)), instant); - return; - } - - rotationRoutine = StartCoroutine(RotateToIndexRoutine(index, instant)); - } - - Coroutine rotationRoutine; - IEnumerator RotateToIndexRoutine(int index, bool instant) - { - rdyToFire = false; - rdyMissile = null; - railIndex = index; - - /* - MissileLauncher foundMissile = null; - - foreach(var mIndex in missileToRailIndex.Keys) - { - if(missileToRailIndex[mIndex] == index) - { - foundMissile = missileChildren[mIndex]; - } - } - nextMissile = foundMissile; - */ - - - - yield return new WaitForSeconds(rotationDelay); - - Quaternion targetRot = Quaternion.Euler(0, 0, (float)index * -railAngle); - - if(instant) - { - for(int i = 0; i < rotationTransforms.Count; i++) - { - rotationTransforms[i].localRotation = targetRot; - } - - UpdateMissilePositions(); - //yield break; - } - else - { - while(rotationTransforms[0].localRotation != targetRot) - { - for(int i = 0; i < rotationTransforms.Count; i++) - { - rotationTransforms[i].localRotation = Quaternion.RotateTowards(rotationTransforms[i].localRotation, targetRot, rotationSpeed * Time.fixedDeltaTime); - } - - UpdateMissilePositions(); - yield return new WaitForFixedUpdate(); - } - } - - if(nextMissile) - { - rdyMissile = nextMissile; - rdyToFire = true; - nextMissile = null; - - if(weaponManager) - { - if(wm.weaponIndex > 0 && wm.selectedWeapon.GetPart().name == rdyMissile.part.name) - { - wm.selectedWeapon = rdyMissile; - wm.currentMissile = rdyMissile; - } - } - } - } - - public void PrepMissileForFire(MissileLauncher ml) - { - if(ml != readyMissile) - { - //Debug.Log("Rotary rail tried prepping a missile for fire, but it is not in firing position"); - return; - } - - int index = IndexOfMissile(ml); - - if(index >= 0) - { - PrepMissileForFire(index); - } - else - { - //Debug.Log("Tried to prep a missile for firing that doesn't exist or is not attached to the turret."); - } - } - - void PrepMissileForFire(int index) - { - //Debug.Log("Prepping missile for rotary rail fire."); - missileChildren[index].part.CoMOffset = comOffsets[missileChildren[index].part]; - - missileTransforms[index].localPosition = Vector3.zero; - missileTransforms[index].localRotation = Quaternion.identity; - missileChildren[index].part.partTransform.position = missileReferenceTransforms[index].position; - missileChildren[index].part.partTransform.rotation = missileReferenceTransforms[index].rotation; - - missileChildren[index].decoupleForward = false; - - missileChildren[index].part.rb.velocity = part.rb.GetPointVelocity(missileReferenceTransforms[index].position); - - missileChildren[index].rotaryRail = this; - } - - public void FireMissile(int missileIndex) - { - int nextRailIndex = 0; - - if(!readyToFire) - { - return; - } - - if(missileIndex >= missileChildren.Length) - { - return; - } - - if(missileIndex < missileCount && missileChildren != null && missileChildren[missileIndex] != null) - { - if(missileChildren[missileIndex] != readyMissile) return; - - PrepMissileForFire(missileIndex); - - if(weaponManager) - { - wm.SendTargetDataToMissile(missileChildren[missileIndex]); - } - - string firedMissileName = missileChildren[missileIndex].part.name; - - missileChildren[missileIndex].FireMissile(); - - rdyMissile = null; - rdyToFire = false; - //StartCoroutine(MissileRailRoutine(missileChildren[missileIndex])); - - nextRailIndex = Mathf.RoundToInt(Mathf.Repeat(missileToRailIndex[missileIndex] + 1, numberOfRails)); - - UpdateMissileChildren(); - - if(wm) - { - wm.UpdateList(); - } - - if(railToMissileIndex.ContainsKey(nextRailIndex) && railToMissileIndex[nextRailIndex] < missileCount && missileChildren[railToMissileIndex[nextRailIndex]].part.name == firedMissileName) - { - RotateToIndex(nextRailIndex, false); - } - } - - - - //StartCoroutine(RotateToIndexAtEndOfFrame(nextRailIndex, false)); - } - - - - IEnumerator RotateToIndexAtEndOfFrame(int index, bool instant) - { - yield return new WaitForEndOfFrame(); - RotateToIndex(index, instant); - } - - public void FireMissile(MissileLauncher ml) - { - if(!readyToFire || ml != readyMissile) - { - return; - } - - - int index = IndexOfMissile(ml); - if(index >= 0) - { - //Debug.Log("Firing missile index: " + index); - FireMissile(index); - } - else - { - //Debug.Log("Tried to fire a missile that doesn't exist or is not attached to the rail."); - } - } - - private int IndexOfMissile(MissileLauncher ml) - { - if(missileCount == 0) return -1; - - for(int i = 0; i < missileCount; i++) - { - if(missileChildren[i] && missileChildren[i] == ml) - { - return i; - } - } - - return -1; - } - - - public void UpdateMissileChildren() - { - missileCount = 0; - - //setup com dictionary - if(comOffsets == null) - { - comOffsets = new Dictionary(); - } - - //destroy the existing reference transform objects - if(missileReferenceTransforms != null) - { - for(int i = 0; i < missileReferenceTransforms.Length; i++) - { - if(missileReferenceTransforms[i]) - { - GameObject.Destroy(missileReferenceTransforms[i].gameObject); - } - } - } - - List msl = new List(); - List mtfl = new List(); - List mrl = new List(); - - foreach(var child in part.children) - { - if(child.parent != part) continue; - - MissileLauncher ml = child.FindModuleImplementing(); - - if(!ml) continue; - - Transform mTf = child.FindModelTransform("missileTransform"); - //fix incorrect hierarchy - if(!mTf) - { - Transform modelTransform = ml.part.partTransform.FindChild("model"); - - mTf = new GameObject("missileTransform").transform; - Transform[] tfchildren = new Transform[modelTransform.childCount]; - for(int i = 0; i < modelTransform.childCount; i++) - { - tfchildren[i] = modelTransform.GetChild(i); - } - mTf.parent = modelTransform; - mTf.localPosition = Vector3.zero; - mTf.localRotation = Quaternion.identity; - mTf.localScale = Vector3.one; - for(int i = 0; i < tfchildren.Length; i++) - { - //Debug.Log("MissileTurret moving transform: " + tfchildren[i].gameObject.name); - tfchildren[i].parent = mTf; - } - } - - if(ml && mTf) - { - msl.Add(ml); - mtfl.Add(mTf); - Transform mRef = new GameObject().transform; - mRef.position = mTf.position; - mRef.rotation = mTf.rotation; - mRef.parent = rotationTransforms[0]; - mrl.Add(mRef); - - ml.missileReferenceTransform = mTf; - ml.rotaryRail = this; - - ml.decoupleForward = false; - ml.decoupleSpeed = Mathf.Max(ml.decoupleSpeed, 4); - ml.dropTime = Mathf.Max(ml.dropTime, 0.2f); - - - if(!comOffsets.ContainsKey(ml.part)) - { - comOffsets.Add(ml.part, ml.part.CoMOffset); - } - - //missileCount++; - } - } - - missileChildren = msl.ToArray(); - missileCount = missileChildren.Length; - missileTransforms = mtfl.ToArray(); - missileReferenceTransforms = mrl.ToArray(); - - UpdateIndexDictionary(); - } - - /* - //editor stuff - void OnPartEnter(Part p) - { - if(EditorLogic.SelectedPart && EditorLogic.SelectedPart!=part) - { - previousSymMethod = EditorLogic.fetch.symmetryMethod; - EditorLogic.fetch.symmetryMethod = SymmetryMethod.Radial; - } - } - void OnPartExit(Part p) - { - if(EditorLogic.SelectedPart && EditorLogic.SelectedPart != part) - { - EditorLogic.fetch.symmetryMethod = previousSymMethod; - } - - if(EditorLogic.fetch.symmetryMethod == SymmetryMethod.Mirror) - { - EditorLogic.fetch.symmetryMode = Mathf.Min(EditorLogic.fetch.symmetryMode, 1); - } - } - SymmetryMethod previousSymMethod; - */ - - //test - void OnGUI() - { - /* - if(HighLogic.LoadedSceneIsEditor) - { - string debugString = "Selected part: " + (EditorLogic.SelectedPart ? EditorLogic.SelectedPart.name : "None"); - - debugString += "\nsymmetryMode: " + EditorLogic.fetch.symmetryMode; - - GUI.Label(new Rect(400, 400, 600, 600), debugString); - } - - */ - /* - if(HighLogic.LoadedSceneIsFlight) - { - if(readyMissile) - { - BDGUIUtils.DrawLineBetweenWorldPositions(readyMissile.missileReferenceTransform.position, readyMissile.missileReferenceTransform.position + readyMissile.missileReferenceTransform.forward, 3, Color.blue); - BDGUIUtils.DrawLineBetweenWorldPositions(readyMissile.missileReferenceTransform.position, readyMissile.missileReferenceTransform.position + readyMissile.missileReferenceTransform.up, 3, Color.green); - - } - - for(int i = 0; i < numberOfRails; i++) - { - Vector3 railPos = part.transform.position + (Quaternion.AngleAxis((float)i*railAngle, part.transform.up) * part.transform.forward); - Vector2 guiPos; - if(BDGUIUtils.WorldToGUIPos(railPos, out guiPos)) - { - GUI.Label(new Rect(guiPos.x, guiPos.y, 20, 20), "R:"+i.ToString()); - } - } - - if(missileCount > 0) - { - for(int i = 0; i < missileCount; i++) - { - MissileLauncher ml = missileChildren[i]; - Vector2 guiPos; - if(BDGUIUtils.WorldToGUIPos(ml.transform.position, out guiPos)) - { - GUI.Label(new Rect(guiPos.x, guiPos.y, 40, 20), "M:"+i.ToString()); - } - } - } - - string rail2MissileString = "Rail to missile\n"; - if(railToMissileIndex != null) - { - foreach(var r in railToMissileIndex.Keys) - { - rail2MissileString += "R: " + r + " M: " + railToMissileIndex[r].ToString() +"\n"; - } - } - GUI.Label(new Rect(200, 200, 200, 900), rail2MissileString); - - string missile2railString = "Missile to rail\n"; - if(missileToRailIndex != null) - { - foreach(var m in missileToRailIndex.Keys) - { - missile2railString += "R: " + missileToRailIndex[m].ToString() + " M: " + m +"\n"; - } - } - GUI.Label(new Rect(500, 200, 200, 900), missile2railString); - }*/ - } - - - void UpdateMissilePositions() - { - if(missileCount == 0) - { - return; - } - - for(int i = 0; i < missileChildren.Length; i++) - { - if(missileTransforms[i] && missileChildren[i] && !missileChildren[i].hasFired) - { - missileTransforms[i].position = missileReferenceTransforms[i].position; - missileTransforms[i].rotation = missileReferenceTransforms[i].rotation; - - Part missilePart = missileChildren[i].part; - Vector3 newCoMOffset = missilePart.transform.InverseTransformPoint(missileTransforms[i].TransformPoint(comOffsets[missilePart])); - missilePart.CoMOffset = newCoMOffset; - } - } - } - - /* - float dropRailLength = 1; - IEnumerator MissileRailRoutine(MissileLauncher ml) - { - yield return null; - Ray ray = new Ray(ml.transform.position, part.transform.forward); - Vector3 localOrigin = part.transform.InverseTransformPoint(ray.origin); - Vector3 localDirection = part.transform.InverseTransformDirection(ray.direction); - float dropSpeed = ml.decoupleSpeed; - while(ml && Vector3.SqrMagnitude(ml.transform.position - ray.origin) < dropRailLength * dropRailLength && ml.timeIndex < ml.dropTime) - { - - //float thrust = ml.timeIndex < ml.boostTime ? ml.thrust : ml.cruiseThrust; - //thrust = ml.timeIndex < ml.boostTime + ml.cruiseTime ? thrust : 0; - //float accel = thrust / ml.part.mass; - //dropSpeed += accel * Time.fixedDeltaTime; - - - ray.origin = part.transform.TransformPoint(localOrigin); - ray.direction = part.transform.TransformDirection(localDirection); - - Vector3 projPos = Vector3.Project(ml.vessel.transform.position - ray.origin, ray.direction) + ray.origin; - Vector3 railVel = part.rb.GetPointVelocity(projPos); - //Vector3 projVel = Vector3.Project(ml.vessel.srf_velocity-railVel, ray.direction); - - ml.vessel.SetPosition(projPos); - ml.vessel.SetWorldVelocity(railVel + (dropSpeed * ray.direction)); - - yield return new WaitForFixedUpdate(); - - ray.origin = part.transform.TransformPoint(localOrigin); - ray.direction = part.transform.TransformDirection(localDirection); - } - } - */ - - } -} - diff --git a/BahaTurret/BahaTurret.csproj b/BahaTurret/BahaTurret.csproj deleted file mode 100644 index 722f00d4b..000000000 --- a/BahaTurret/BahaTurret.csproj +++ /dev/null @@ -1,146 +0,0 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {D86F2003-1724-4F4C-BB5A-B0109CB16F35} - Library - BahaTurret - BahaTurret - v3.5 - - - True - full - False - bin\Debug - DEBUG; - prompt - 4 - x86 - False - - - none - False - bin\Release - prompt - 4 - x86 - False - - - - - - ..\..\..\Program Files\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\UnityEngine.dll - - - ..\..\..\Program Files\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\Assembly-CSharp.dll - - - ..\..\..\Program Files\Steam\SteamApps\common\Kerbal Space Program\KSP_x64_Data\Managed\KSPCore.dll - - - ..\..\..\Program Files\Steam\steamapps\common\Kerbal Space Program\KSP_x64_Data\Managed\KSPUtil.dll - - - ..\..\..\Program Files\Steam\steamapps\common\Kerbal Space Program\KSP_x64_Data\Managed\Assembly-CSharp-firstpass.dll - - - ..\..\..\Program Files\Steam\steamapps\common\Kerbal Space Program\KSP_x64_Data\Managed\UnityEngine.UI.dll - - - ..\..\..\Program Files\Steam\SteamApps\common\Kerbal Space Program\KSP_x64_Data\Managed\KSPAssets.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/BahaTurret/BahaTurret.sln b/BahaTurret/BahaTurret.sln deleted file mode 100644 index 6a23f58eb..000000000 --- a/BahaTurret/BahaTurret.sln +++ /dev/null @@ -1,17 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BahaTurret", "BahaTurret.csproj", "{D86F2003-1724-4F4C-BB5A-B0109CB16F35}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Debug|x86.ActiveCfg = Debug|x86 - {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Debug|x86.Build.0 = Debug|x86 - {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Release|x86.ActiveCfg = Release|x86 - {D86F2003-1724-4F4C-BB5A-B0109CB16F35}.Release|x86.Build.0 = Release|x86 - EndGlobalSection -EndGlobal diff --git a/BahaTurret/BahaTurret.v12.suo b/BahaTurret/BahaTurret.v12.suo deleted file mode 100644 index 0295dee77..000000000 Binary files a/BahaTurret/BahaTurret.v12.suo and /dev/null differ diff --git a/BahaTurret/BulletHitFX.cs b/BahaTurret/BulletHitFX.cs deleted file mode 100644 index dbaa3ac9e..000000000 --- a/BahaTurret/BulletHitFX.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class BulletHitFX : MonoBehaviour - { - KSPParticleEmitter[] pEmitters; - AudioSource audioSource; - AudioClip hitSound; - public Vector3 normal; - float startTime; - public bool ricochet; - - //static GameObject go = GameDatabase.Instance.GetModel("BDArmory/Models/bulletHit/bulletHit"); //===TODO: static object wont load after scene reload - - void Start() - { - startTime = Time.time; - pEmitters = gameObject.GetComponentsInChildren(); - audioSource = gameObject.AddComponent(); - audioSource.minDistance = 1; - audioSource.maxDistance = 50; - audioSource.spatialBlend = 1; - audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - - int random = UnityEngine.Random.Range(1,3); - - if(ricochet) - { - string path = "BDArmory/Sounds/ricochet" + random; - hitSound = GameDatabase.Instance.GetAudioClip(path); - } - else - { - string path = "BDArmory/Sounds/bulletHit" + random; - hitSound = GameDatabase.Instance.GetAudioClip(path); - } - - - - audioSource.PlayOneShot(hitSound); - - } - - void Update() - { - if(Time.time - startTime > 0.03f) - { - foreach(KSPParticleEmitter pe in pEmitters) - { - pe.emit = false; - } - } - - if(Time.time - startTime > 2f) - { - Destroy(gameObject); - } - } - - public static void CreateBulletHit(Vector3 position, Vector3 normalDirection, bool ricochet) - { - GameObject go = GameDatabase.Instance.GetModel("BDArmory/Models/bulletHit/bulletHit"); - GameObject newExplosion = (GameObject) GameObject.Instantiate(go, position, Quaternion.LookRotation(normalDirection)); - newExplosion.SetActive(true); - newExplosion.AddComponent(); - newExplosion.GetComponent().ricochet = ricochet; - foreach(KSPParticleEmitter pe in newExplosion.GetComponentsInChildren()) - { - pe.emit = true; - if(pe.gameObject.name == "sparks") - { - pe.force = (4.49f * FlightGlobals.getGeeForceAtPosition(position)); - } - else if(pe.gameObject.name == "smoke") - { - pe.force = (1.49f * FlightGlobals.getGeeForceAtPosition(position)); - } - } - } - - } -} - diff --git a/BahaTurret/BulletShader.shader b/BahaTurret/BulletShader.shader deleted file mode 100644 index 539d79d64..000000000 --- a/BahaTurret/BulletShader.shader +++ /dev/null @@ -1,1825 +0,0 @@ -Shader "BDArmory/Particles/Bullet" -{ - Properties - { - _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5) - _MainTex ("Particle Texture", 2D) = "white" {} - _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0 - _Lum ("Luminance", float) = 1 - } - - Category - { - Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } - //Blend SrcAlpha OneMinusSrcAlpha - //Blend SrcAlpha One - Blend SrcAlpha OneMinusSrcColor - AlphaTest Greater .01 - ColorMask RGB - Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) } - BindChannels { - Bind "Color", color - Bind "Vertex", vertex - Bind "TexCoord", texcoord - } - - // ---- Fragment program cards - SubShader - { - Pass - { - - Program "vp" { -// Vertex combos: 2 -// opengl - ALU: 6 to 14 -// d3d9 - ALU: 6 to 14 -// d3d11 - ALU: 1 to 6, TEX: 0 to 0, FLOW: 1 to 1 -// d3d11_9x - ALU: 1 to 6, TEX: 0 to 0, FLOW: 1 to 1 -SubProgram "opengl " { -Keywords { "SOFTPARTICLES_OFF" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -Vector 5 [_MainTex_ST] -"!!ARBvp1.0 -# 6 ALU -PARAM c[6] = { program.local[0], - state.matrix.mvp, - program.local[5] }; -MOV result.color, vertex.color; -MAD result.texcoord[0].xy, vertex.texcoord[0], c[5], c[5].zwzw; -DP4 result.position.w, vertex.position, c[4]; -DP4 result.position.z, vertex.position, c[3]; -DP4 result.position.y, vertex.position, c[2]; -DP4 result.position.x, vertex.position, c[1]; -END -# 6 instructions, 0 R-regs -" -} - -SubProgram "d3d9 " { -Keywords { "SOFTPARTICLES_OFF" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -Matrix 0 [glstate_matrix_mvp] -Vector 4 [_MainTex_ST] -"vs_2_0 -; 6 ALU -dcl_position0 v0 -dcl_color0 v1 -dcl_texcoord0 v2 -mov oD0, v1 -mad oT0.xy, v2, c4, c4.zwzw -dp4 oPos.w, v0, c3 -dp4 oPos.z, v0, c2 -dp4 oPos.y, v0, c1 -dp4 oPos.x, v0, c0 -" -} - -SubProgram "d3d11 " { -Keywords { "SOFTPARTICLES_OFF" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -ConstBuffer "$Globals" 64 // 48 used size, 5 vars -Vector 32 [_MainTex_ST] 4 -ConstBuffer "UnityPerDraw" 336 // 64 used size, 6 vars -Matrix 0 [glstate_matrix_mvp] 4 -BindCB "$Globals" 0 -BindCB "UnityPerDraw" 1 -// 7 instructions, 1 temp regs, 0 temp arrays: -// ALU 1 float, 0 int, 0 uint -// TEX 0 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"vs_4_0 -eefieceddoellgnlfilkjcnhpflcklipjanghigmabaaaaaahaacaaaaadaaaaaa -cmaaaaaajmaaaaaabaabaaaaejfdeheogiaaaaaaadaaaaaaaiaaaaaafaaaaaaa -aaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapapaaaafjaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaapapaaaafpaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaa -adadaaaafaepfdejfeejepeoaaedepemepfcaafeeffiedepepfceeaaepfdeheo -gmaaaaaaadaaaaaaaiaaaaaafaaaaaaaaaaaaaaaabaaaaaaadaaaaaaaaaaaaaa -apaaaaaafmaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaapaaaaaagcaaaaaa -aaaaaaaaaaaaaaaaadaaaaaaacaaaaaaadamaaaafdfgfpfagphdgjhegjgpgoaa -edepemepfcaafeeffiedepepfceeaaklfdeieefcfiabaaaaeaaaabaafgaaaaaa -fjaaaaaeegiocaaaaaaaaaaaadaaaaaafjaaaaaeegiocaaaabaaaaaaaeaaaaaa -fpaaaaadpcbabaaaaaaaaaaafpaaaaadpcbabaaaabaaaaaafpaaaaaddcbabaaa -acaaaaaaghaaaaaepccabaaaaaaaaaaaabaaaaaagfaaaaadpccabaaaabaaaaaa -gfaaaaaddccabaaaacaaaaaagiaaaaacabaaaaaadiaaaaaipcaabaaaaaaaaaaa -fgbfbaaaaaaaaaaaegiocaaaabaaaaaaabaaaaaadcaaaaakpcaabaaaaaaaaaaa -egiocaaaabaaaaaaaaaaaaaaagbabaaaaaaaaaaaegaobaaaaaaaaaaadcaaaaak -pcaabaaaaaaaaaaaegiocaaaabaaaaaaacaaaaaakgbkbaaaaaaaaaaaegaobaaa -aaaaaaaadcaaaaakpccabaaaaaaaaaaaegiocaaaabaaaaaaadaaaaaapgbpbaaa -aaaaaaaaegaobaaaaaaaaaaadgaaaaafpccabaaaabaaaaaaegbobaaaabaaaaaa -dcaaaaaldccabaaaacaaaaaaegbabaaaacaaaaaaegiacaaaaaaaaaaaacaaaaaa -ogikcaaaaaaaaaaaacaaaaaadoaaaaab" -} - -SubProgram "gles " { -Keywords { "SOFTPARTICLES_OFF" } -"!!GLES - - -#ifdef VERTEX - -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp vec4 _MainTex_ST; -uniform highp mat4 glstate_matrix_mvp; -attribute vec4 _glesMultiTexCoord0; -attribute vec4 _glesColor; -attribute vec4 _glesVertex; -void main () -{ - gl_Position = (glstate_matrix_mvp * _glesVertex); - xlv_COLOR = _glesColor; - xlv_TEXCOORD0 = ((_glesMultiTexCoord0.xy * _MainTex_ST.xy) + _MainTex_ST.zw); -} - - - -#endif -#ifdef FRAGMENT - -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp float _Lum; -uniform lowp vec4 _TintColor; -uniform sampler2D _MainTex; -void main () -{ - lowp vec4 tint_1; - lowp vec4 tmpvar_2; - tmpvar_2 = texture2D (_MainTex, xlv_TEXCOORD0); - lowp float tmpvar_3; - tmpvar_3 = dot (tmpvar_2.xyz, vec3(0.22, 0.707, 0.071)); - tint_1.w = _TintColor.w; - highp vec3 tmpvar_4; - tmpvar_4 = (_TintColor.xyz + clamp (((tmpvar_3 * _Lum) - 1.0), 0.0, 1.0)); - tint_1.xyz = tmpvar_4; - highp vec4 tmpvar_5; - tmpvar_5 = (tint_1 * _Lum); - tint_1 = tmpvar_5; - gl_FragData[0] = (((2.0 * xlv_COLOR) * tmpvar_2) * tint_1); -} - - - -#endif" -} - -SubProgram "glesdesktop " { -Keywords { "SOFTPARTICLES_OFF" } -"!!GLES - - -#ifdef VERTEX - -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp vec4 _MainTex_ST; -uniform highp mat4 glstate_matrix_mvp; -attribute vec4 _glesMultiTexCoord0; -attribute vec4 _glesColor; -attribute vec4 _glesVertex; -void main () -{ - gl_Position = (glstate_matrix_mvp * _glesVertex); - xlv_COLOR = _glesColor; - xlv_TEXCOORD0 = ((_glesMultiTexCoord0.xy * _MainTex_ST.xy) + _MainTex_ST.zw); -} - - - -#endif -#ifdef FRAGMENT - -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp float _Lum; -uniform lowp vec4 _TintColor; -uniform sampler2D _MainTex; -void main () -{ - lowp vec4 tint_1; - lowp vec4 tmpvar_2; - tmpvar_2 = texture2D (_MainTex, xlv_TEXCOORD0); - lowp float tmpvar_3; - tmpvar_3 = dot (tmpvar_2.xyz, vec3(0.22, 0.707, 0.071)); - tint_1.w = _TintColor.w; - highp vec3 tmpvar_4; - tmpvar_4 = (_TintColor.xyz + clamp (((tmpvar_3 * _Lum) - 1.0), 0.0, 1.0)); - tint_1.xyz = tmpvar_4; - highp vec4 tmpvar_5; - tmpvar_5 = (tint_1 * _Lum); - tint_1 = tmpvar_5; - gl_FragData[0] = (((2.0 * xlv_COLOR) * tmpvar_2) * tint_1); -} - - - -#endif" -} - -SubProgram "flash " { -Keywords { "SOFTPARTICLES_OFF" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -Matrix 0 [glstate_matrix_mvp] -Vector 4 [_MainTex_ST] -"agal_vs -[bc] -aaaaaaaaahaaapaeacaaaaoeaaaaaaaaaaaaaaaaaaaaaaaa mov v7, a2 -adaaaaaaaaaaadacadaaaaoeaaaaaaaaaeaaaaoeabaaaaaa mul r0.xy, a3, c4 -abaaaaaaaaaaadaeaaaaaafeacaaaaaaaeaaaaooabaaaaaa add v0.xy, r0.xyyy, c4.zwzw -bdaaaaaaaaaaaiadaaaaaaoeaaaaaaaaadaaaaoeabaaaaaa dp4 o0.w, a0, c3 -bdaaaaaaaaaaaeadaaaaaaoeaaaaaaaaacaaaaoeabaaaaaa dp4 o0.z, a0, c2 -bdaaaaaaaaaaacadaaaaaaoeaaaaaaaaabaaaaoeabaaaaaa dp4 o0.y, a0, c1 -bdaaaaaaaaaaabadaaaaaaoeaaaaaaaaaaaaaaoeabaaaaaa dp4 o0.x, a0, c0 -aaaaaaaaaaaaamaeaaaaaaoeabaaaaaaaaaaaaaaaaaaaaaa mov v0.zw, c0 -" -} - -SubProgram "d3d11_9x " { -Keywords { "SOFTPARTICLES_OFF" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -ConstBuffer "$Globals" 64 // 48 used size, 5 vars -Vector 32 [_MainTex_ST] 4 -ConstBuffer "UnityPerDraw" 336 // 64 used size, 6 vars -Matrix 0 [glstate_matrix_mvp] 4 -BindCB "$Globals" 0 -BindCB "UnityPerDraw" 1 -// 7 instructions, 1 temp regs, 0 temp arrays: -// ALU 1 float, 0 int, 0 uint -// TEX 0 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"vs_4_0_level_9_1 -eefiecedaohmkcmlcibmkipbenhacfnehadnaapgabaaaaaaheadaaaaaeaaaaaa -daaaaaaadaabaaaajaacaaaaaaadaaaaebgpgodjpiaaaaaapiaaaaaaaaacpopp -liaaaaaaeaaaaaaaacaaceaaaaaadmaaaaaadmaaaaaaceaaabaadmaaaaaaacaa -abaaabaaaaaaaaaaabaaaaaaaeaaacaaaaaaaaaaaaaaaaaaaaacpoppbpaaaaac -afaaaaiaaaaaapjabpaaaaacafaaabiaabaaapjabpaaaaacafaaaciaacaaapja -aeaaaaaeabaaadoaacaaoejaabaaoekaabaaookaafaaaaadaaaaapiaaaaaffja -adaaoekaaeaaaaaeaaaaapiaacaaoekaaaaaaajaaaaaoeiaaeaaaaaeaaaaapia -aeaaoekaaaaakkjaaaaaoeiaaeaaaaaeaaaaapiaafaaoekaaaaappjaaaaaoeia -aeaaaaaeaaaaadmaaaaappiaaaaaoekaaaaaoeiaabaaaaacaaaaammaaaaaoeia -abaaaaacaaaaapoaabaaoejappppaaaafdeieefcfiabaaaaeaaaabaafgaaaaaa -fjaaaaaeegiocaaaaaaaaaaaadaaaaaafjaaaaaeegiocaaaabaaaaaaaeaaaaaa -fpaaaaadpcbabaaaaaaaaaaafpaaaaadpcbabaaaabaaaaaafpaaaaaddcbabaaa -acaaaaaaghaaaaaepccabaaaaaaaaaaaabaaaaaagfaaaaadpccabaaaabaaaaaa -gfaaaaaddccabaaaacaaaaaagiaaaaacabaaaaaadiaaaaaipcaabaaaaaaaaaaa -fgbfbaaaaaaaaaaaegiocaaaabaaaaaaabaaaaaadcaaaaakpcaabaaaaaaaaaaa -egiocaaaabaaaaaaaaaaaaaaagbabaaaaaaaaaaaegaobaaaaaaaaaaadcaaaaak -pcaabaaaaaaaaaaaegiocaaaabaaaaaaacaaaaaakgbkbaaaaaaaaaaaegaobaaa -aaaaaaaadcaaaaakpccabaaaaaaaaaaaegiocaaaabaaaaaaadaaaaaapgbpbaaa -aaaaaaaaegaobaaaaaaaaaaadgaaaaafpccabaaaabaaaaaaegbobaaaabaaaaaa -dcaaaaaldccabaaaacaaaaaaegbabaaaacaaaaaaegiacaaaaaaaaaaaacaaaaaa -ogikcaaaaaaaaaaaacaaaaaadoaaaaabejfdeheogiaaaaaaadaaaaaaaiaaaaaa -faaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapapaaaafjaaaaaaaaaaaaaa -aaaaaaaaadaaaaaaabaaaaaaapapaaaafpaaaaaaaaaaaaaaaaaaaaaaadaaaaaa -acaaaaaaadadaaaafaepfdejfeejepeoaaedepemepfcaafeeffiedepepfceeaa -epfdeheogmaaaaaaadaaaaaaaiaaaaaafaaaaaaaaaaaaaaaabaaaaaaadaaaaaa -aaaaaaaaapaaaaaafmaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaapaaaaaa -gcaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaaadamaaaafdfgfpfagphdgjhe -gjgpgoaaedepemepfcaafeeffiedepepfceeaakl" -} - -SubProgram "gles3 " { -Keywords { "SOFTPARTICLES_OFF" } -"!!GLES3#version 300 es - - -#ifdef VERTEX - -#define gl_Vertex _glesVertex -in vec4 _glesVertex; -#define gl_Color _glesColor -in vec4 _glesColor; -#define gl_MultiTexCoord0 _glesMultiTexCoord0 -in vec4 _glesMultiTexCoord0; - -#line 150 -struct v2f_vertex_lit { - highp vec2 uv; - lowp vec4 diff; - lowp vec4 spec; -}; -#line 186 -struct v2f_img { - highp vec4 pos; - mediump vec2 uv; -}; -#line 180 -struct appdata_img { - highp vec4 vertex; - mediump vec2 texcoord; -}; -#line 315 -struct v2f { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; -}; -#line 308 -struct appdata_t { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; -}; -uniform highp vec4 _Time; -uniform highp vec4 _SinTime; -#line 3 -uniform highp vec4 _CosTime; -uniform highp vec4 unity_DeltaTime; -uniform highp vec3 _WorldSpaceCameraPos; -uniform highp vec4 _ProjectionParams; -#line 7 -uniform highp vec4 _ScreenParams; -uniform highp vec4 _ZBufferParams; -uniform highp vec4 unity_CameraWorldClipPlanes[6]; -uniform highp vec4 _WorldSpaceLightPos0; -#line 11 -uniform highp vec4 _LightPositionRange; -uniform highp vec4 unity_4LightPosX0; -uniform highp vec4 unity_4LightPosY0; -uniform highp vec4 unity_4LightPosZ0; -#line 15 -uniform highp vec4 unity_4LightAtten0; -uniform highp vec4 unity_LightColor[4]; -uniform highp vec4 unity_LightPosition[4]; -uniform highp vec4 unity_LightAtten[4]; -#line 19 -uniform highp vec4 unity_SHAr; -uniform highp vec4 unity_SHAg; -uniform highp vec4 unity_SHAb; -uniform highp vec4 unity_SHBr; -#line 23 -uniform highp vec4 unity_SHBg; -uniform highp vec4 unity_SHBb; -uniform highp vec4 unity_SHC; -uniform highp vec3 unity_LightColor0; -uniform highp vec3 unity_LightColor1; -uniform highp vec3 unity_LightColor2; -uniform highp vec3 unity_LightColor3; -#line 27 -uniform highp vec4 unity_ShadowSplitSpheres[4]; -uniform highp vec4 unity_ShadowSplitSqRadii; -uniform highp vec4 unity_LightShadowBias; -uniform highp vec4 _LightSplitsNear; -#line 31 -uniform highp vec4 _LightSplitsFar; -uniform highp mat4 unity_World2Shadow[4]; -uniform highp vec4 _LightShadowData; -uniform highp vec4 unity_ShadowFadeCenterAndType; -#line 35 -uniform highp mat4 glstate_matrix_mvp; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_invtrans_modelview0; -uniform highp mat4 _Object2World; -#line 39 -uniform highp mat4 _World2Object; -uniform highp vec4 unity_Scale; -uniform highp mat4 glstate_matrix_transpose_modelview0; -uniform highp mat4 glstate_matrix_texture0; -#line 43 -uniform highp mat4 glstate_matrix_texture1; -uniform highp mat4 glstate_matrix_texture2; -uniform highp mat4 glstate_matrix_texture3; -uniform highp mat4 glstate_matrix_projection; -#line 47 -uniform highp vec4 glstate_lightmodel_ambient; -uniform highp mat4 unity_MatrixV; -uniform highp mat4 unity_MatrixVP; -uniform lowp vec4 unity_ColorSpaceGrey; -#line 76 -#line 81 -#line 86 -#line 90 -#line 95 -#line 119 -#line 136 -#line 157 -#line 165 -#line 192 -#line 205 -#line 214 -#line 219 -#line 228 -#line 233 -#line 242 -#line 259 -#line 264 -#line 290 -#line 298 -#line 302 -#line 306 -uniform sampler2D _MainTex; -uniform lowp vec4 _TintColor; -#line 322 -uniform highp vec4 _MainTex_ST; -#line 331 -uniform sampler2D _CameraDepthTexture; -uniform highp float _InvFade; -uniform highp float _Lum; -#line 323 -v2f vert( in appdata_t v ) { - v2f o; - #line 326 - o.vertex = (glstate_matrix_mvp * v.vertex); - o.color = v.color; - o.texcoord = ((v.texcoord.xy * _MainTex_ST.xy) + _MainTex_ST.zw); - return o; -} -out lowp vec4 xlv_COLOR; -out highp vec2 xlv_TEXCOORD0; -void main() { - v2f xl_retval; - appdata_t xlt_v; - xlt_v.vertex = vec4(gl_Vertex); - xlt_v.color = vec4(gl_Color); - xlt_v.texcoord = vec2(gl_MultiTexCoord0); - xl_retval = vert( xlt_v); - gl_Position = vec4(xl_retval.vertex); - xlv_COLOR = vec4(xl_retval.color); - xlv_TEXCOORD0 = vec2(xl_retval.texcoord); -} - - -#endif -#ifdef FRAGMENT - -#define gl_FragData _glesFragData -layout(location = 0) out mediump vec4 _glesFragData[4]; - -#line 150 -struct v2f_vertex_lit { - highp vec2 uv; - lowp vec4 diff; - lowp vec4 spec; -}; -#line 186 -struct v2f_img { - highp vec4 pos; - mediump vec2 uv; -}; -#line 180 -struct appdata_img { - highp vec4 vertex; - mediump vec2 texcoord; -}; -#line 315 -struct v2f { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; -}; -#line 308 -struct appdata_t { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; -}; -uniform highp vec4 _Time; -uniform highp vec4 _SinTime; -#line 3 -uniform highp vec4 _CosTime; -uniform highp vec4 unity_DeltaTime; -uniform highp vec3 _WorldSpaceCameraPos; -uniform highp vec4 _ProjectionParams; -#line 7 -uniform highp vec4 _ScreenParams; -uniform highp vec4 _ZBufferParams; -uniform highp vec4 unity_CameraWorldClipPlanes[6]; -uniform highp vec4 _WorldSpaceLightPos0; -#line 11 -uniform highp vec4 _LightPositionRange; -uniform highp vec4 unity_4LightPosX0; -uniform highp vec4 unity_4LightPosY0; -uniform highp vec4 unity_4LightPosZ0; -#line 15 -uniform highp vec4 unity_4LightAtten0; -uniform highp vec4 unity_LightColor[4]; -uniform highp vec4 unity_LightPosition[4]; -uniform highp vec4 unity_LightAtten[4]; -#line 19 -uniform highp vec4 unity_SHAr; -uniform highp vec4 unity_SHAg; -uniform highp vec4 unity_SHAb; -uniform highp vec4 unity_SHBr; -#line 23 -uniform highp vec4 unity_SHBg; -uniform highp vec4 unity_SHBb; -uniform highp vec4 unity_SHC; -uniform highp vec3 unity_LightColor0; -uniform highp vec3 unity_LightColor1; -uniform highp vec3 unity_LightColor2; -uniform highp vec3 unity_LightColor3; -#line 27 -uniform highp vec4 unity_ShadowSplitSpheres[4]; -uniform highp vec4 unity_ShadowSplitSqRadii; -uniform highp vec4 unity_LightShadowBias; -uniform highp vec4 _LightSplitsNear; -#line 31 -uniform highp vec4 _LightSplitsFar; -uniform highp mat4 unity_World2Shadow[4]; -uniform highp vec4 _LightShadowData; -uniform highp vec4 unity_ShadowFadeCenterAndType; -#line 35 -uniform highp mat4 glstate_matrix_mvp; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_invtrans_modelview0; -uniform highp mat4 _Object2World; -#line 39 -uniform highp mat4 _World2Object; -uniform highp vec4 unity_Scale; -uniform highp mat4 glstate_matrix_transpose_modelview0; -uniform highp mat4 glstate_matrix_texture0; -#line 43 -uniform highp mat4 glstate_matrix_texture1; -uniform highp mat4 glstate_matrix_texture2; -uniform highp mat4 glstate_matrix_texture3; -uniform highp mat4 glstate_matrix_projection; -#line 47 -uniform highp vec4 glstate_lightmodel_ambient; -uniform highp mat4 unity_MatrixV; -uniform highp mat4 unity_MatrixVP; -uniform lowp vec4 unity_ColorSpaceGrey; -#line 76 -#line 81 -#line 86 -#line 90 -#line 95 -#line 119 -#line 136 -#line 157 -#line 165 -#line 192 -#line 205 -#line 214 -#line 219 -#line 228 -#line 233 -#line 242 -#line 259 -#line 264 -#line 290 -#line 298 -#line 302 -#line 306 -uniform sampler2D _MainTex; -uniform lowp vec4 _TintColor; -#line 322 -uniform highp vec4 _MainTex_ST; -#line 331 -uniform sampler2D _CameraDepthTexture; -uniform highp float _InvFade; -uniform highp float _Lum; -#line 172 -lowp float Luminance( in lowp vec3 c ) { - #line 174 - return dot( c, vec3( 0.22, 0.707, 0.071)); -} -#line 334 -lowp vec4 frag( in v2f i ) { - #line 336 - lowp vec4 texCol = texture( _MainTex, i.texcoord); - highp float over = clamp( ((Luminance( vec3( texCol)) * _Lum) - 1.0), 0.0, 1.0); - lowp vec4 tint = _TintColor; - tint.xyz += (1.0 * over); - #line 340 - tint *= _Lum; - return (((2.0 * i.color) * texCol) * tint); -} -in lowp vec4 xlv_COLOR; -in highp vec2 xlv_TEXCOORD0; -void main() { - lowp vec4 xl_retval; - v2f xlt_i; - xlt_i.vertex = vec4(0.0); - xlt_i.color = vec4(xlv_COLOR); - xlt_i.texcoord = vec2(xlv_TEXCOORD0); - xl_retval = frag( xlt_i); - gl_FragData[0] = vec4(xl_retval); -} - - -#endif" -} - -SubProgram "opengl " { -Keywords { "SOFTPARTICLES_ON" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -Vector 9 [_ProjectionParams] -Vector 10 [_MainTex_ST] -"!!ARBvp1.0 -# 14 ALU -PARAM c[11] = { { 0.5 }, - state.matrix.modelview[0], - state.matrix.mvp, - program.local[9..10] }; -TEMP R0; -TEMP R1; -DP4 R1.w, vertex.position, c[8]; -DP4 R0.x, vertex.position, c[5]; -MOV R0.w, R1; -DP4 R0.y, vertex.position, c[6]; -MUL R1.xyz, R0.xyww, c[0].x; -MUL R1.y, R1, c[9].x; -DP4 R0.z, vertex.position, c[7]; -MOV result.position, R0; -DP4 R0.x, vertex.position, c[3]; -ADD result.texcoord[1].xy, R1, R1.z; -MOV result.color, vertex.color; -MAD result.texcoord[0].xy, vertex.texcoord[0], c[10], c[10].zwzw; -MOV result.texcoord[1].z, -R0.x; -MOV result.texcoord[1].w, R1; -END -# 14 instructions, 2 R-regs -" -} - -SubProgram "d3d9 " { -Keywords { "SOFTPARTICLES_ON" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -Matrix 0 [glstate_matrix_modelview0] -Matrix 4 [glstate_matrix_mvp] -Vector 8 [_ProjectionParams] -Vector 9 [_ScreenParams] -Vector 10 [_MainTex_ST] -"vs_2_0 -; 14 ALU -def c11, 0.50000000, 0, 0, 0 -dcl_position0 v0 -dcl_color0 v1 -dcl_texcoord0 v2 -dp4 r1.w, v0, c7 -dp4 r0.x, v0, c4 -mov r0.w, r1 -dp4 r0.y, v0, c5 -mul r1.xyz, r0.xyww, c11.x -mul r1.y, r1, c8.x -dp4 r0.z, v0, c6 -mov oPos, r0 -dp4 r0.x, v0, c2 -mad oT1.xy, r1.z, c9.zwzw, r1 -mov oD0, v1 -mad oT0.xy, v2, c10, c10.zwzw -mov oT1.z, -r0.x -mov oT1.w, r1 -" -} - -SubProgram "d3d11 " { -Keywords { "SOFTPARTICLES_ON" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -ConstBuffer "$Globals" 64 // 48 used size, 5 vars -Vector 32 [_MainTex_ST] 4 -ConstBuffer "UnityPerCamera" 128 // 96 used size, 8 vars -Vector 80 [_ProjectionParams] 4 -ConstBuffer "UnityPerDraw" 336 // 128 used size, 6 vars -Matrix 0 [glstate_matrix_mvp] 4 -Matrix 64 [glstate_matrix_modelview0] 4 -BindCB "$Globals" 0 -BindCB "UnityPerCamera" 1 -BindCB "UnityPerDraw" 2 -// 17 instructions, 2 temp regs, 0 temp arrays: -// ALU 6 float, 0 int, 0 uint -// TEX 0 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"vs_4_0 -eefiecednmpbjacibpimicngiphdfdihadeeendaabaaaaaaoaadaaaaadaaaaaa -cmaaaaaajmaaaaaaciabaaaaejfdeheogiaaaaaaadaaaaaaaiaaaaaafaaaaaaa -aaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapapaaaafjaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaapapaaaafpaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaa -adadaaaafaepfdejfeejepeoaaedepemepfcaafeeffiedepepfceeaaepfdeheo -ieaaaaaaaeaaaaaaaiaaaaaagiaaaaaaaaaaaaaaabaaaaaaadaaaaaaaaaaaaaa -apaaaaaaheaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaapaaaaaahkaaaaaa -aaaaaaaaaaaaaaaaadaaaaaaacaaaaaaadamaaaahkaaaaaaabaaaaaaaaaaaaaa -adaaaaaaadaaaaaaapaaaaaafdfgfpfagphdgjhegjgpgoaaedepemepfcaafeef -fiedepepfceeaaklfdeieefclaacaaaaeaaaabaakmaaaaaafjaaaaaeegiocaaa -aaaaaaaaadaaaaaafjaaaaaeegiocaaaabaaaaaaagaaaaaafjaaaaaeegiocaaa -acaaaaaaaiaaaaaafpaaaaadpcbabaaaaaaaaaaafpaaaaadpcbabaaaabaaaaaa -fpaaaaaddcbabaaaacaaaaaaghaaaaaepccabaaaaaaaaaaaabaaaaaagfaaaaad -pccabaaaabaaaaaagfaaaaaddccabaaaacaaaaaagfaaaaadpccabaaaadaaaaaa -giaaaaacacaaaaaadiaaaaaipcaabaaaaaaaaaaafgbfbaaaaaaaaaaaegiocaaa -acaaaaaaabaaaaaadcaaaaakpcaabaaaaaaaaaaaegiocaaaacaaaaaaaaaaaaaa -agbabaaaaaaaaaaaegaobaaaaaaaaaaadcaaaaakpcaabaaaaaaaaaaaegiocaaa -acaaaaaaacaaaaaakgbkbaaaaaaaaaaaegaobaaaaaaaaaaadcaaaaakpcaabaaa -aaaaaaaaegiocaaaacaaaaaaadaaaaaapgbpbaaaaaaaaaaaegaobaaaaaaaaaaa -dgaaaaafpccabaaaaaaaaaaaegaobaaaaaaaaaaadgaaaaafpccabaaaabaaaaaa -egbobaaaabaaaaaadcaaaaaldccabaaaacaaaaaaegbabaaaacaaaaaaegiacaaa -aaaaaaaaacaaaaaaogikcaaaaaaaaaaaacaaaaaadiaaaaaiccaabaaaaaaaaaaa -bkaabaaaaaaaaaaaakiacaaaabaaaaaaafaaaaaadiaaaaakncaabaaaabaaaaaa -agahbaaaaaaaaaaaaceaaaaaaaaaaadpaaaaaaaaaaaaaadpaaaaaadpdgaaaaaf -iccabaaaadaaaaaadkaabaaaaaaaaaaaaaaaaaahdccabaaaadaaaaaakgakbaaa -abaaaaaamgaabaaaabaaaaaadiaaaaaibcaabaaaaaaaaaaabkbabaaaaaaaaaaa -ckiacaaaacaaaaaaafaaaaaadcaaaaakbcaabaaaaaaaaaaackiacaaaacaaaaaa -aeaaaaaaakbabaaaaaaaaaaaakaabaaaaaaaaaaadcaaaaakbcaabaaaaaaaaaaa -ckiacaaaacaaaaaaagaaaaaackbabaaaaaaaaaaaakaabaaaaaaaaaaadcaaaaak -bcaabaaaaaaaaaaackiacaaaacaaaaaaahaaaaaadkbabaaaaaaaaaaaakaabaaa -aaaaaaaadgaaaaageccabaaaadaaaaaaakaabaiaebaaaaaaaaaaaaaadoaaaaab -" -} - -SubProgram "gles " { -Keywords { "SOFTPARTICLES_ON" } -"!!GLES - - -#ifdef VERTEX - -varying highp vec4 xlv_TEXCOORD1; -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp vec4 _MainTex_ST; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_mvp; -uniform highp vec4 _ProjectionParams; -attribute vec4 _glesMultiTexCoord0; -attribute vec4 _glesColor; -attribute vec4 _glesVertex; -void main () -{ - highp vec4 tmpvar_1; - highp vec4 tmpvar_2; - tmpvar_2 = (glstate_matrix_mvp * _glesVertex); - highp vec4 o_3; - highp vec4 tmpvar_4; - tmpvar_4 = (tmpvar_2 * 0.5); - highp vec2 tmpvar_5; - tmpvar_5.x = tmpvar_4.x; - tmpvar_5.y = (tmpvar_4.y * _ProjectionParams.x); - o_3.xy = (tmpvar_5 + tmpvar_4.w); - o_3.zw = tmpvar_2.zw; - tmpvar_1.xyw = o_3.xyw; - tmpvar_1.z = -((glstate_matrix_modelview0 * _glesVertex).z); - gl_Position = tmpvar_2; - xlv_COLOR = _glesColor; - xlv_TEXCOORD0 = ((_glesMultiTexCoord0.xy * _MainTex_ST.xy) + _MainTex_ST.zw); - xlv_TEXCOORD1 = tmpvar_1; -} - - - -#endif -#ifdef FRAGMENT - -varying highp vec4 xlv_TEXCOORD1; -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp float _Lum; -uniform highp float _InvFade; -uniform sampler2D _CameraDepthTexture; -uniform lowp vec4 _TintColor; -uniform sampler2D _MainTex; -uniform highp vec4 _ZBufferParams; -void main () -{ - lowp vec4 tmpvar_1; - tmpvar_1.xyz = xlv_COLOR.xyz; - lowp vec4 tint_2; - lowp vec4 tmpvar_3; - tmpvar_3 = texture2DProj (_CameraDepthTexture, xlv_TEXCOORD1); - highp float z_4; - z_4 = tmpvar_3.x; - highp float tmpvar_5; - tmpvar_5 = (xlv_COLOR.w * clamp ((_InvFade * ((1.0/(((_ZBufferParams.z * z_4) + _ZBufferParams.w))) - xlv_TEXCOORD1.z)), 0.0, 1.0)); - tmpvar_1.w = tmpvar_5; - lowp vec4 tmpvar_6; - tmpvar_6 = texture2D (_MainTex, xlv_TEXCOORD0); - lowp float tmpvar_7; - tmpvar_7 = dot (tmpvar_6.xyz, vec3(0.22, 0.707, 0.071)); - tint_2.w = _TintColor.w; - highp vec3 tmpvar_8; - tmpvar_8 = (_TintColor.xyz + clamp (((tmpvar_7 * _Lum) - 1.0), 0.0, 1.0)); - tint_2.xyz = tmpvar_8; - highp vec4 tmpvar_9; - tmpvar_9 = (tint_2 * _Lum); - tint_2 = tmpvar_9; - gl_FragData[0] = (((2.0 * tmpvar_1) * tmpvar_6) * tint_2); -} - - - -#endif" -} - -SubProgram "glesdesktop " { -Keywords { "SOFTPARTICLES_ON" } -"!!GLES - - -#ifdef VERTEX - -varying highp vec4 xlv_TEXCOORD1; -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp vec4 _MainTex_ST; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_mvp; -uniform highp vec4 _ProjectionParams; -attribute vec4 _glesMultiTexCoord0; -attribute vec4 _glesColor; -attribute vec4 _glesVertex; -void main () -{ - highp vec4 tmpvar_1; - highp vec4 tmpvar_2; - tmpvar_2 = (glstate_matrix_mvp * _glesVertex); - highp vec4 o_3; - highp vec4 tmpvar_4; - tmpvar_4 = (tmpvar_2 * 0.5); - highp vec2 tmpvar_5; - tmpvar_5.x = tmpvar_4.x; - tmpvar_5.y = (tmpvar_4.y * _ProjectionParams.x); - o_3.xy = (tmpvar_5 + tmpvar_4.w); - o_3.zw = tmpvar_2.zw; - tmpvar_1.xyw = o_3.xyw; - tmpvar_1.z = -((glstate_matrix_modelview0 * _glesVertex).z); - gl_Position = tmpvar_2; - xlv_COLOR = _glesColor; - xlv_TEXCOORD0 = ((_glesMultiTexCoord0.xy * _MainTex_ST.xy) + _MainTex_ST.zw); - xlv_TEXCOORD1 = tmpvar_1; -} - - - -#endif -#ifdef FRAGMENT - -varying highp vec4 xlv_TEXCOORD1; -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec4 xlv_COLOR; -uniform highp float _Lum; -uniform highp float _InvFade; -uniform sampler2D _CameraDepthTexture; -uniform lowp vec4 _TintColor; -uniform sampler2D _MainTex; -uniform highp vec4 _ZBufferParams; -void main () -{ - lowp vec4 tmpvar_1; - tmpvar_1.xyz = xlv_COLOR.xyz; - lowp vec4 tint_2; - lowp vec4 tmpvar_3; - tmpvar_3 = texture2DProj (_CameraDepthTexture, xlv_TEXCOORD1); - highp float z_4; - z_4 = tmpvar_3.x; - highp float tmpvar_5; - tmpvar_5 = (xlv_COLOR.w * clamp ((_InvFade * ((1.0/(((_ZBufferParams.z * z_4) + _ZBufferParams.w))) - xlv_TEXCOORD1.z)), 0.0, 1.0)); - tmpvar_1.w = tmpvar_5; - lowp vec4 tmpvar_6; - tmpvar_6 = texture2D (_MainTex, xlv_TEXCOORD0); - lowp float tmpvar_7; - tmpvar_7 = dot (tmpvar_6.xyz, vec3(0.22, 0.707, 0.071)); - tint_2.w = _TintColor.w; - highp vec3 tmpvar_8; - tmpvar_8 = (_TintColor.xyz + clamp (((tmpvar_7 * _Lum) - 1.0), 0.0, 1.0)); - tint_2.xyz = tmpvar_8; - highp vec4 tmpvar_9; - tmpvar_9 = (tint_2 * _Lum); - tint_2 = tmpvar_9; - gl_FragData[0] = (((2.0 * tmpvar_1) * tmpvar_6) * tint_2); -} - - - -#endif" -} - -SubProgram "flash " { -Keywords { "SOFTPARTICLES_ON" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -Matrix 0 [glstate_matrix_modelview0] -Matrix 4 [glstate_matrix_mvp] -Vector 8 [_ProjectionParams] -Vector 9 [unity_NPOTScale] -Vector 10 [_MainTex_ST] -"agal_vs -c11 0.5 0.0 0.0 0.0 -[bc] -bdaaaaaaabaaaiacaaaaaaoeaaaaaaaaahaaaaoeabaaaaaa dp4 r1.w, a0, c7 -bdaaaaaaaaaaabacaaaaaaoeaaaaaaaaaeaaaaoeabaaaaaa dp4 r0.x, a0, c4 -aaaaaaaaaaaaaiacabaaaappacaaaaaaaaaaaaaaaaaaaaaa mov r0.w, r1.w -bdaaaaaaaaaaacacaaaaaaoeaaaaaaaaafaaaaoeabaaaaaa dp4 r0.y, a0, c5 -adaaaaaaabaaahacaaaaaapeacaaaaaaalaaaaaaabaaaaaa mul r1.xyz, r0.xyww, c11.x -adaaaaaaabaaacacabaaaaffacaaaaaaaiaaaaaaabaaaaaa mul r1.y, r1.y, c8.x -abaaaaaaabaaadacabaaaafeacaaaaaaabaaaakkacaaaaaa add r1.xy, r1.xyyy, r1.z -bdaaaaaaaaaaaeacaaaaaaoeaaaaaaaaagaaaaoeabaaaaaa dp4 r0.z, a0, c6 -aaaaaaaaaaaaapadaaaaaaoeacaaaaaaaaaaaaaaaaaaaaaa mov o0, r0 -bdaaaaaaaaaaabacaaaaaaoeaaaaaaaaacaaaaoeabaaaaaa dp4 r0.x, a0, c2 -adaaaaaaabaaadaeabaaaafeacaaaaaaajaaaaoeabaaaaaa mul v1.xy, r1.xyyy, c9 -aaaaaaaaahaaapaeacaaaaoeaaaaaaaaaaaaaaaaaaaaaaaa mov v7, a2 -adaaaaaaacaaadacadaaaaoeaaaaaaaaakaaaaoeabaaaaaa mul r2.xy, a3, c10 -abaaaaaaaaaaadaeacaaaafeacaaaaaaakaaaaooabaaaaaa add v0.xy, r2.xyyy, c10.zwzw -bfaaaaaaabaaaeaeaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaa neg v1.z, r0.x -aaaaaaaaabaaaiaeabaaaappacaaaaaaaaaaaaaaaaaaaaaa mov v1.w, r1.w -aaaaaaaaaaaaamaeaaaaaaoeabaaaaaaaaaaaaaaaaaaaaaa mov v0.zw, c0 -" -} - -SubProgram "d3d11_9x " { -Keywords { "SOFTPARTICLES_ON" } -Bind "vertex" Vertex -Bind "color" Color -Bind "texcoord" TexCoord0 -ConstBuffer "$Globals" 64 // 48 used size, 5 vars -Vector 32 [_MainTex_ST] 4 -ConstBuffer "UnityPerCamera" 128 // 96 used size, 8 vars -Vector 80 [_ProjectionParams] 4 -ConstBuffer "UnityPerDraw" 336 // 128 used size, 6 vars -Matrix 0 [glstate_matrix_mvp] 4 -Matrix 64 [glstate_matrix_modelview0] 4 -BindCB "$Globals" 0 -BindCB "UnityPerCamera" 1 -BindCB "UnityPerDraw" 2 -// 17 instructions, 2 temp regs, 0 temp arrays: -// ALU 6 float, 0 int, 0 uint -// TEX 0 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"vs_4_0_level_9_1 -eefiecedebcippahhcnnkilpdplfokklbbpcocajabaaaaaakmafaaaaaeaaaaaa -daaaaaaapiabaaaalaaeaaaacaafaaaaebgpgodjmaabaaaamaabaaaaaaacpopp -heabaaaaemaaaaaaadaaceaaaaaaeiaaaaaaeiaaaaaaceaaabaaeiaaaaaaacaa -abaaabaaaaaaaaaaabaaafaaabaaacaaaaaaaaaaacaaaaaaaiaaadaaaaaaaaaa -aaaaaaaaaaacpoppfbaaaaafalaaapkaaaaaaadpaaaaaaaaaaaaaaaaaaaaaaaa -bpaaaaacafaaaaiaaaaaapjabpaaaaacafaaabiaabaaapjabpaaaaacafaaacia -acaaapjaafaaaaadaaaaapiaaaaaffjaaeaaoekaaeaaaaaeaaaaapiaadaaoeka -aaaaaajaaaaaoeiaaeaaaaaeaaaaapiaafaaoekaaaaakkjaaaaaoeiaaeaaaaae -aaaaapiaagaaoekaaaaappjaaaaaoeiaafaaaaadabaaabiaaaaaffiaacaaaaka -afaaaaadabaaaiiaabaaaaiaalaaaakaafaaaaadabaaafiaaaaapeiaalaaaaka -acaaaaadacaaadoaabaakkiaabaaomiaafaaaaadabaaabiaaaaaffjaaiaakkka -aeaaaaaeabaaabiaahaakkkaaaaaaajaabaaaaiaaeaaaaaeabaaabiaajaakkka -aaaakkjaabaaaaiaaeaaaaaeabaaabiaakaakkkaaaaappjaabaaaaiaabaaaaac -acaaaeoaabaaaaibaeaaaaaeabaaadoaacaaoejaabaaoekaabaaookaaeaaaaae -aaaaadmaaaaappiaaaaaoekaaaaaoeiaabaaaaacaaaaammaaaaaoeiaabaaaaac -acaaaioaaaaappiaabaaaaacaaaaapoaabaaoejappppaaaafdeieefclaacaaaa -eaaaabaakmaaaaaafjaaaaaeegiocaaaaaaaaaaaadaaaaaafjaaaaaeegiocaaa -abaaaaaaagaaaaaafjaaaaaeegiocaaaacaaaaaaaiaaaaaafpaaaaadpcbabaaa -aaaaaaaafpaaaaadpcbabaaaabaaaaaafpaaaaaddcbabaaaacaaaaaaghaaaaae -pccabaaaaaaaaaaaabaaaaaagfaaaaadpccabaaaabaaaaaagfaaaaaddccabaaa -acaaaaaagfaaaaadpccabaaaadaaaaaagiaaaaacacaaaaaadiaaaaaipcaabaaa -aaaaaaaafgbfbaaaaaaaaaaaegiocaaaacaaaaaaabaaaaaadcaaaaakpcaabaaa -aaaaaaaaegiocaaaacaaaaaaaaaaaaaaagbabaaaaaaaaaaaegaobaaaaaaaaaaa -dcaaaaakpcaabaaaaaaaaaaaegiocaaaacaaaaaaacaaaaaakgbkbaaaaaaaaaaa -egaobaaaaaaaaaaadcaaaaakpcaabaaaaaaaaaaaegiocaaaacaaaaaaadaaaaaa -pgbpbaaaaaaaaaaaegaobaaaaaaaaaaadgaaaaafpccabaaaaaaaaaaaegaobaaa -aaaaaaaadgaaaaafpccabaaaabaaaaaaegbobaaaabaaaaaadcaaaaaldccabaaa -acaaaaaaegbabaaaacaaaaaaegiacaaaaaaaaaaaacaaaaaaogikcaaaaaaaaaaa -acaaaaaadiaaaaaiccaabaaaaaaaaaaabkaabaaaaaaaaaaaakiacaaaabaaaaaa -afaaaaaadiaaaaakncaabaaaabaaaaaaagahbaaaaaaaaaaaaceaaaaaaaaaaadp -aaaaaaaaaaaaaadpaaaaaadpdgaaaaaficcabaaaadaaaaaadkaabaaaaaaaaaaa -aaaaaaahdccabaaaadaaaaaakgakbaaaabaaaaaamgaabaaaabaaaaaadiaaaaai -bcaabaaaaaaaaaaabkbabaaaaaaaaaaackiacaaaacaaaaaaafaaaaaadcaaaaak -bcaabaaaaaaaaaaackiacaaaacaaaaaaaeaaaaaaakbabaaaaaaaaaaaakaabaaa -aaaaaaaadcaaaaakbcaabaaaaaaaaaaackiacaaaacaaaaaaagaaaaaackbabaaa -aaaaaaaaakaabaaaaaaaaaaadcaaaaakbcaabaaaaaaaaaaackiacaaaacaaaaaa -ahaaaaaadkbabaaaaaaaaaaaakaabaaaaaaaaaaadgaaaaageccabaaaadaaaaaa -akaabaiaebaaaaaaaaaaaaaadoaaaaabejfdeheogiaaaaaaadaaaaaaaiaaaaaa -faaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapapaaaafjaaaaaaaaaaaaaa -aaaaaaaaadaaaaaaabaaaaaaapapaaaafpaaaaaaaaaaaaaaaaaaaaaaadaaaaaa -acaaaaaaadadaaaafaepfdejfeejepeoaaedepemepfcaafeeffiedepepfceeaa -epfdeheoieaaaaaaaeaaaaaaaiaaaaaagiaaaaaaaaaaaaaaabaaaaaaadaaaaaa -aaaaaaaaapaaaaaaheaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaapaaaaaa -hkaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaaadamaaaahkaaaaaaabaaaaaa -aaaaaaaaadaaaaaaadaaaaaaapaaaaaafdfgfpfagphdgjhegjgpgoaaedepemep -fcaafeeffiedepepfceeaakl" -} - -SubProgram "gles3 " { -Keywords { "SOFTPARTICLES_ON" } -"!!GLES3#version 300 es - - -#ifdef VERTEX - -#define gl_Vertex _glesVertex -in vec4 _glesVertex; -#define gl_Color _glesColor -in vec4 _glesColor; -#define gl_MultiTexCoord0 _glesMultiTexCoord0 -in vec4 _glesMultiTexCoord0; - -#line 150 -struct v2f_vertex_lit { - highp vec2 uv; - lowp vec4 diff; - lowp vec4 spec; -}; -#line 186 -struct v2f_img { - highp vec4 pos; - mediump vec2 uv; -}; -#line 180 -struct appdata_img { - highp vec4 vertex; - mediump vec2 texcoord; -}; -#line 315 -struct v2f { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; - highp vec4 projPos; -}; -#line 308 -struct appdata_t { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; -}; -uniform highp vec4 _Time; -uniform highp vec4 _SinTime; -#line 3 -uniform highp vec4 _CosTime; -uniform highp vec4 unity_DeltaTime; -uniform highp vec3 _WorldSpaceCameraPos; -uniform highp vec4 _ProjectionParams; -#line 7 -uniform highp vec4 _ScreenParams; -uniform highp vec4 _ZBufferParams; -uniform highp vec4 unity_CameraWorldClipPlanes[6]; -uniform highp vec4 _WorldSpaceLightPos0; -#line 11 -uniform highp vec4 _LightPositionRange; -uniform highp vec4 unity_4LightPosX0; -uniform highp vec4 unity_4LightPosY0; -uniform highp vec4 unity_4LightPosZ0; -#line 15 -uniform highp vec4 unity_4LightAtten0; -uniform highp vec4 unity_LightColor[4]; -uniform highp vec4 unity_LightPosition[4]; -uniform highp vec4 unity_LightAtten[4]; -#line 19 -uniform highp vec4 unity_SHAr; -uniform highp vec4 unity_SHAg; -uniform highp vec4 unity_SHAb; -uniform highp vec4 unity_SHBr; -#line 23 -uniform highp vec4 unity_SHBg; -uniform highp vec4 unity_SHBb; -uniform highp vec4 unity_SHC; -uniform highp vec3 unity_LightColor0; -uniform highp vec3 unity_LightColor1; -uniform highp vec3 unity_LightColor2; -uniform highp vec3 unity_LightColor3; -#line 27 -uniform highp vec4 unity_ShadowSplitSpheres[4]; -uniform highp vec4 unity_ShadowSplitSqRadii; -uniform highp vec4 unity_LightShadowBias; -uniform highp vec4 _LightSplitsNear; -#line 31 -uniform highp vec4 _LightSplitsFar; -uniform highp mat4 unity_World2Shadow[4]; -uniform highp vec4 _LightShadowData; -uniform highp vec4 unity_ShadowFadeCenterAndType; -#line 35 -uniform highp mat4 glstate_matrix_mvp; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_invtrans_modelview0; -uniform highp mat4 _Object2World; -#line 39 -uniform highp mat4 _World2Object; -uniform highp vec4 unity_Scale; -uniform highp mat4 glstate_matrix_transpose_modelview0; -uniform highp mat4 glstate_matrix_texture0; -#line 43 -uniform highp mat4 glstate_matrix_texture1; -uniform highp mat4 glstate_matrix_texture2; -uniform highp mat4 glstate_matrix_texture3; -uniform highp mat4 glstate_matrix_projection; -#line 47 -uniform highp vec4 glstate_lightmodel_ambient; -uniform highp mat4 unity_MatrixV; -uniform highp mat4 unity_MatrixVP; -uniform lowp vec4 unity_ColorSpaceGrey; -#line 76 -#line 81 -#line 86 -#line 90 -#line 95 -#line 119 -#line 136 -#line 157 -#line 165 -#line 192 -#line 205 -#line 214 -#line 219 -#line 228 -#line 233 -#line 242 -#line 259 -#line 264 -#line 290 -#line 298 -#line 302 -#line 306 -uniform sampler2D _MainTex; -uniform lowp vec4 _TintColor; -#line 323 -uniform highp vec4 _MainTex_ST; -uniform sampler2D _CameraDepthTexture; -#line 335 -uniform highp float _InvFade; -uniform highp float _Lum; -#line 283 -highp vec4 ComputeScreenPos( in highp vec4 pos ) { - #line 285 - highp vec4 o = (pos * 0.5); - o.xy = (vec2( o.x, (o.y * _ProjectionParams.x)) + o.w); - o.zw = pos.zw; - return o; -} -#line 324 -v2f vert( in appdata_t v ) { - v2f o; - #line 327 - o.vertex = (glstate_matrix_mvp * v.vertex); - o.projPos = ComputeScreenPos( o.vertex); - o.projPos.z = (-(glstate_matrix_modelview0 * v.vertex).z); - o.color = v.color; - #line 331 - o.texcoord = ((v.texcoord.xy * _MainTex_ST.xy) + _MainTex_ST.zw); - return o; -} -out lowp vec4 xlv_COLOR; -out highp vec2 xlv_TEXCOORD0; -out highp vec4 xlv_TEXCOORD1; -void main() { - v2f xl_retval; - appdata_t xlt_v; - xlt_v.vertex = vec4(gl_Vertex); - xlt_v.color = vec4(gl_Color); - xlt_v.texcoord = vec2(gl_MultiTexCoord0); - xl_retval = vert( xlt_v); - gl_Position = vec4(xl_retval.vertex); - xlv_COLOR = vec4(xl_retval.color); - xlv_TEXCOORD0 = vec2(xl_retval.texcoord); - xlv_TEXCOORD1 = vec4(xl_retval.projPos); -} - - -#endif -#ifdef FRAGMENT - -#define gl_FragData _glesFragData -layout(location = 0) out mediump vec4 _glesFragData[4]; -float xll_saturate_f( float x) { - return clamp( x, 0.0, 1.0); -} -vec2 xll_saturate_vf2( vec2 x) { - return clamp( x, 0.0, 1.0); -} -vec3 xll_saturate_vf3( vec3 x) { - return clamp( x, 0.0, 1.0); -} -vec4 xll_saturate_vf4( vec4 x) { - return clamp( x, 0.0, 1.0); -} -mat2 xll_saturate_mf2x2(mat2 m) { - return mat2( clamp(m[0], 0.0, 1.0), clamp(m[1], 0.0, 1.0)); -} -mat3 xll_saturate_mf3x3(mat3 m) { - return mat3( clamp(m[0], 0.0, 1.0), clamp(m[1], 0.0, 1.0), clamp(m[2], 0.0, 1.0)); -} -mat4 xll_saturate_mf4x4(mat4 m) { - return mat4( clamp(m[0], 0.0, 1.0), clamp(m[1], 0.0, 1.0), clamp(m[2], 0.0, 1.0), clamp(m[3], 0.0, 1.0)); -} -#line 150 -struct v2f_vertex_lit { - highp vec2 uv; - lowp vec4 diff; - lowp vec4 spec; -}; -#line 186 -struct v2f_img { - highp vec4 pos; - mediump vec2 uv; -}; -#line 180 -struct appdata_img { - highp vec4 vertex; - mediump vec2 texcoord; -}; -#line 315 -struct v2f { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; - highp vec4 projPos; -}; -#line 308 -struct appdata_t { - highp vec4 vertex; - lowp vec4 color; - highp vec2 texcoord; -}; -uniform highp vec4 _Time; -uniform highp vec4 _SinTime; -#line 3 -uniform highp vec4 _CosTime; -uniform highp vec4 unity_DeltaTime; -uniform highp vec3 _WorldSpaceCameraPos; -uniform highp vec4 _ProjectionParams; -#line 7 -uniform highp vec4 _ScreenParams; -uniform highp vec4 _ZBufferParams; -uniform highp vec4 unity_CameraWorldClipPlanes[6]; -uniform highp vec4 _WorldSpaceLightPos0; -#line 11 -uniform highp vec4 _LightPositionRange; -uniform highp vec4 unity_4LightPosX0; -uniform highp vec4 unity_4LightPosY0; -uniform highp vec4 unity_4LightPosZ0; -#line 15 -uniform highp vec4 unity_4LightAtten0; -uniform highp vec4 unity_LightColor[4]; -uniform highp vec4 unity_LightPosition[4]; -uniform highp vec4 unity_LightAtten[4]; -#line 19 -uniform highp vec4 unity_SHAr; -uniform highp vec4 unity_SHAg; -uniform highp vec4 unity_SHAb; -uniform highp vec4 unity_SHBr; -#line 23 -uniform highp vec4 unity_SHBg; -uniform highp vec4 unity_SHBb; -uniform highp vec4 unity_SHC; -uniform highp vec3 unity_LightColor0; -uniform highp vec3 unity_LightColor1; -uniform highp vec3 unity_LightColor2; -uniform highp vec3 unity_LightColor3; -#line 27 -uniform highp vec4 unity_ShadowSplitSpheres[4]; -uniform highp vec4 unity_ShadowSplitSqRadii; -uniform highp vec4 unity_LightShadowBias; -uniform highp vec4 _LightSplitsNear; -#line 31 -uniform highp vec4 _LightSplitsFar; -uniform highp mat4 unity_World2Shadow[4]; -uniform highp vec4 _LightShadowData; -uniform highp vec4 unity_ShadowFadeCenterAndType; -#line 35 -uniform highp mat4 glstate_matrix_mvp; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_invtrans_modelview0; -uniform highp mat4 _Object2World; -#line 39 -uniform highp mat4 _World2Object; -uniform highp vec4 unity_Scale; -uniform highp mat4 glstate_matrix_transpose_modelview0; -uniform highp mat4 glstate_matrix_texture0; -#line 43 -uniform highp mat4 glstate_matrix_texture1; -uniform highp mat4 glstate_matrix_texture2; -uniform highp mat4 glstate_matrix_texture3; -uniform highp mat4 glstate_matrix_projection; -#line 47 -uniform highp vec4 glstate_lightmodel_ambient; -uniform highp mat4 unity_MatrixV; -uniform highp mat4 unity_MatrixVP; -uniform lowp vec4 unity_ColorSpaceGrey; -#line 76 -#line 81 -#line 86 -#line 90 -#line 95 -#line 119 -#line 136 -#line 157 -#line 165 -#line 192 -#line 205 -#line 214 -#line 219 -#line 228 -#line 233 -#line 242 -#line 259 -#line 264 -#line 290 -#line 298 -#line 302 -#line 306 -uniform sampler2D _MainTex; -uniform lowp vec4 _TintColor; -#line 323 -uniform highp vec4 _MainTex_ST; -uniform sampler2D _CameraDepthTexture; -#line 335 -uniform highp float _InvFade; -uniform highp float _Lum; -#line 279 -highp float LinearEyeDepth( in highp float z ) { - #line 281 - return (1.0 / ((_ZBufferParams.z * z) + _ZBufferParams.w)); -} -#line 172 -lowp float Luminance( in lowp vec3 c ) { - #line 174 - return dot( c, vec3( 0.22, 0.707, 0.071)); -} -#line 337 -lowp vec4 frag( in v2f i ) { - #line 339 - highp float sceneZ = LinearEyeDepth( textureProj( _CameraDepthTexture, i.projPos).x); - highp float partZ = i.projPos.z; - highp float fade = xll_saturate_f((_InvFade * (sceneZ - partZ))); - i.color.w *= fade; - #line 343 - lowp vec4 texCol = texture( _MainTex, i.texcoord); - highp float over = clamp( ((Luminance( vec3( texCol)) * _Lum) - 1.0), 0.0, 1.0); - lowp vec4 tint = _TintColor; - tint.xyz += (1.0 * over); - #line 347 - tint *= _Lum; - return (((2.0 * i.color) * texCol) * tint); -} -in lowp vec4 xlv_COLOR; -in highp vec2 xlv_TEXCOORD0; -in highp vec4 xlv_TEXCOORD1; -void main() { - lowp vec4 xl_retval; - v2f xlt_i; - xlt_i.vertex = vec4(0.0); - xlt_i.color = vec4(xlv_COLOR); - xlt_i.texcoord = vec2(xlv_TEXCOORD0); - xlt_i.projPos = vec4(xlv_TEXCOORD1); - xl_retval = frag( xlt_i); - gl_FragData[0] = vec4(xl_retval); -} - - -#endif" -} - -} -Program "fp" { -// Fragment combos: 2 -// opengl - ALU: 10 to 17, TEX: 1 to 2 -// d3d9 - ALU: 10 to 16, TEX: 1 to 2 -// d3d11 - ALU: 7 to 12, TEX: 1 to 2, FLOW: 1 to 1 -// d3d11_9x - ALU: 7 to 12, TEX: 1 to 2, FLOW: 1 to 1 -SubProgram "opengl " { -Keywords { "SOFTPARTICLES_OFF" } -Vector 0 [_TintColor] -Float 1 [_Lum] -SetTexture 0 [_MainTex] 2D -"!!ARBfp1.0 -OPTION ARB_precision_hint_fastest; -# 10 ALU, 1 TEX -PARAM c[4] = { program.local[0..1], - { 0.2199707, 0.70703125, 0.070983887, 1 }, - { 2 } }; -TEMP R0; -TEMP R1; -TEX R0, fragment.texcoord[0], texture[0], 2D; -DP3 R1.x, R0, c[2]; -MUL R1.x, R1, c[1]; -ADD_SAT R1.x, R1, -c[2].w; -MOV R1.w, c[0]; -ADD R1.xyz, R1.x, c[0]; -MUL R1, R1, c[1].x; -MUL R0, fragment.color.primary, R0; -MUL R0, R0, R1; -MUL result.color, R0, c[3].x; -END -# 10 instructions, 2 R-regs -" -} - -SubProgram "d3d9 " { -Keywords { "SOFTPARTICLES_OFF" } -Vector 0 [_TintColor] -Float 1 [_Lum] -SetTexture 0 [_MainTex] 2D -"ps_2_0 -; 10 ALU, 1 TEX -dcl_2d s0 -def c2, 0.21997070, 0.70703125, 0.07098389, -1.00000000 -def c3, 2.00000000, 0, 0, 0 -dcl v0 -dcl t0.xy -texld r1, t0, s0 -dp3_pp r0.x, r1, c2 -mul r0.x, r0, c1 -add_sat r0.x, r0, c2.w -mov_pp r0.w, c0 -add_pp r0.xyz, r0.x, c0 -mul_pp r0, r0, c1.x -mul r1, v0, r1 -mul r0, r1, r0 -mul r0, r0, c3.x -mov_pp oC0, r0 -" -} - -SubProgram "d3d11 " { -Keywords { "SOFTPARTICLES_OFF" } -ConstBuffer "$Globals" 64 // 56 used size, 5 vars -Vector 16 [_TintColor] 4 -Float 52 [_Lum] -BindCB "$Globals" 0 -SetTexture 0 [_MainTex] 2D 0 -// 10 instructions, 3 temp regs, 0 temp arrays: -// ALU 7 float, 0 int, 0 uint -// TEX 1 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"ps_4_0 -eefiecedmdakghemilkegljihilbadmgppimpmlaabaaaaaagmacaaaaadaaaaaa -cmaaaaaakaaaaaaaneaaaaaaejfdeheogmaaaaaaadaaaaaaaiaaaaaafaaaaaaa -aaaaaaaaabaaaaaaadaaaaaaaaaaaaaaapaaaaaafmaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaapapaaaagcaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaa -adadaaaafdfgfpfagphdgjhegjgpgoaaedepemepfcaafeeffiedepepfceeaakl -epfdeheocmaaaaaaabaaaaaaaiaaaaaacaaaaaaaaaaaaaaaaaaaaaaaadaaaaaa -aaaaaaaaapaaaaaafdfgfpfegbhcghgfheaaklklfdeieefcjaabaaaaeaaaaaaa -geaaaaaafjaaaaaeegiocaaaaaaaaaaaaeaaaaaafkaaaaadaagabaaaaaaaaaaa -fibiaaaeaahabaaaaaaaaaaaffffaaaagcbaaaadpcbabaaaabaaaaaagcbaaaad -dcbabaaaacaaaaaagfaaaaadpccabaaaaaaaaaaagiaaaaacadaaaaaaefaaaaaj -pcaabaaaaaaaaaaaegbabaaaacaaaaaaeghobaaaaaaaaaaaaagabaaaaaaaaaaa -baaaaaakbcaabaaaabaaaaaaegacbaaaaaaaaaaaaceaaaaakoehgbdopepndedp -hdgijbdnaaaaaaaadccaaaakbcaabaaaabaaaaaaakaabaaaabaaaaaabkiacaaa -aaaaaaaaadaaaaaaabeaaaaaaaaaialpaaaaaaaihcaabaaaabaaaaaaagaabaaa -abaaaaaaegiccaaaaaaaaaaaabaaaaaadiaaaaaihcaabaaaabaaaaaaegacbaaa -abaaaaaafgifcaaaaaaaaaaaadaaaaaadiaaaaajicaabaaaabaaaaaadkiacaaa -aaaaaaaaabaaaaaabkiacaaaaaaaaaaaadaaaaaaaaaaaaahpcaabaaaacaaaaaa -egbobaaaabaaaaaaegbobaaaabaaaaaadiaaaaahpcaabaaaaaaaaaaaegaobaaa -aaaaaaaaegaobaaaacaaaaaadiaaaaahpccabaaaaaaaaaaaegaobaaaabaaaaaa -egaobaaaaaaaaaaadoaaaaab" -} - -SubProgram "gles " { -Keywords { "SOFTPARTICLES_OFF" } -"!!GLES" -} - -SubProgram "glesdesktop " { -Keywords { "SOFTPARTICLES_OFF" } -"!!GLES" -} - -SubProgram "flash " { -Keywords { "SOFTPARTICLES_OFF" } -Vector 0 [_TintColor] -Float 1 [_Lum] -SetTexture 0 [_MainTex] 2D -"agal_ps -c2 0.219971 0.707031 0.070984 -1.0 -c3 2.0 0.0 0.0 0.0 -[bc] -ciaaaaaaabaaapacaaaaaaoeaeaaaaaaaaaaaaaaafaababb tex r1, v0, s0 <2d wrap linear point> -bcaaaaaaaaaaabacabaaaakeacaaaaaaacaaaaoeabaaaaaa dp3 r0.x, r1.xyzz, c2 -adaaaaaaaaaaabacaaaaaaaaacaaaaaaabaaaaoeabaaaaaa mul r0.x, r0.x, c1 -abaaaaaaaaaaabacaaaaaaaaacaaaaaaacaaaappabaaaaaa add r0.x, r0.x, c2.w -bgaaaaaaaaaaabacaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaa sat r0.x, r0.x -aaaaaaaaaaaaaiacaaaaaaoeabaaaaaaaaaaaaaaaaaaaaaa mov r0.w, c0 -abaaaaaaaaaaahacaaaaaaaaacaaaaaaaaaaaaoeabaaaaaa add r0.xyz, r0.x, c0 -adaaaaaaaaaaapacaaaaaaoeacaaaaaaabaaaaaaabaaaaaa mul r0, r0, c1.x -adaaaaaaabaaapacahaaaaoeaeaaaaaaabaaaaoeacaaaaaa mul r1, v7, r1 -adaaaaaaaaaaapacabaaaaoeacaaaaaaaaaaaaoeacaaaaaa mul r0, r1, r0 -adaaaaaaaaaaapacaaaaaaoeacaaaaaaadaaaaaaabaaaaaa mul r0, r0, c3.x -aaaaaaaaaaaaapadaaaaaaoeacaaaaaaaaaaaaaaaaaaaaaa mov o0, r0 -" -} - -SubProgram "d3d11_9x " { -Keywords { "SOFTPARTICLES_OFF" } -ConstBuffer "$Globals" 64 // 56 used size, 5 vars -Vector 16 [_TintColor] 4 -Float 52 [_Lum] -BindCB "$Globals" 0 -SetTexture 0 [_MainTex] 2D 0 -// 10 instructions, 3 temp regs, 0 temp arrays: -// ALU 7 float, 0 int, 0 uint -// TEX 1 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"ps_4_0_level_9_1 -eefiecedgcnnngnjnpafcdpmblihpmkiclmpgbepabaaaaaakiadaaaaaeaaaaaa -daaaaaaagiabaaaaaaadaaaaheadaaaaebgpgodjdaabaaaadaabaaaaaaacpppp -paaaaaaaeaaaaaaaacaaciaaaaaaeaaaaaaaeaaaabaaceaaaaaaeaaaaaaaaaaa -aaaaabaaabaaaaaaaaaaaaaaaaaaadaaabaaabaaaaaaaaaaaaacppppfbaaaaaf -acaaapkakoehgbdopepndedphdgijbdnaaaaialpbpaaaaacaaaaaaiaaaaaapla -bpaaaaacaaaaaaiaabaaadlabpaaaaacaaaaaajaaaaiapkaecaaaaadaaaacpia -abaaoelaaaaioekaaiaaaaadabaaciiaaaaaoeiaacaaoekaabaaaaacabaaacia -abaaffkaaeaaaaaeabaabbiaabaappiaabaaffiaacaappkaacaaaaadacaachia -abaaaaiaaaaaoekaafaaaaadacaachiaacaaoeiaabaaffkaafaaaaadacaaciia -abaaffiaaaaappkaacaaaaadabaaapiaaaaaoelaaaaaoelaafaaaaadaaaaapia -aaaaoeiaabaaoeiaafaaaaadaaaacpiaacaaoeiaaaaaoeiaabaaaaacaaaicpia -aaaaoeiappppaaaafdeieefcjaabaaaaeaaaaaaageaaaaaafjaaaaaeegiocaaa -aaaaaaaaaeaaaaaafkaaaaadaagabaaaaaaaaaaafibiaaaeaahabaaaaaaaaaaa -ffffaaaagcbaaaadpcbabaaaabaaaaaagcbaaaaddcbabaaaacaaaaaagfaaaaad -pccabaaaaaaaaaaagiaaaaacadaaaaaaefaaaaajpcaabaaaaaaaaaaaegbabaaa -acaaaaaaeghobaaaaaaaaaaaaagabaaaaaaaaaaabaaaaaakbcaabaaaabaaaaaa -egacbaaaaaaaaaaaaceaaaaakoehgbdopepndedphdgijbdnaaaaaaaadccaaaak -bcaabaaaabaaaaaaakaabaaaabaaaaaabkiacaaaaaaaaaaaadaaaaaaabeaaaaa -aaaaialpaaaaaaaihcaabaaaabaaaaaaagaabaaaabaaaaaaegiccaaaaaaaaaaa -abaaaaaadiaaaaaihcaabaaaabaaaaaaegacbaaaabaaaaaafgifcaaaaaaaaaaa -adaaaaaadiaaaaajicaabaaaabaaaaaadkiacaaaaaaaaaaaabaaaaaabkiacaaa -aaaaaaaaadaaaaaaaaaaaaahpcaabaaaacaaaaaaegbobaaaabaaaaaaegbobaaa -abaaaaaadiaaaaahpcaabaaaaaaaaaaaegaobaaaaaaaaaaaegaobaaaacaaaaaa -diaaaaahpccabaaaaaaaaaaaegaobaaaabaaaaaaegaobaaaaaaaaaaadoaaaaab -ejfdeheogmaaaaaaadaaaaaaaiaaaaaafaaaaaaaaaaaaaaaabaaaaaaadaaaaaa -aaaaaaaaapaaaaaafmaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaapapaaaa -gcaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaaadadaaaafdfgfpfagphdgjhe -gjgpgoaaedepemepfcaafeeffiedepepfceeaaklepfdeheocmaaaaaaabaaaaaa -aiaaaaaacaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapaaaaaafdfgfpfe -gbhcghgfheaaklkl" -} - -SubProgram "gles3 " { -Keywords { "SOFTPARTICLES_OFF" } -"!!GLES3" -} - -SubProgram "opengl " { -Keywords { "SOFTPARTICLES_ON" } -Vector 0 [_ZBufferParams] -Vector 1 [_TintColor] -Float 2 [_InvFade] -Float 3 [_Lum] -SetTexture 0 [_CameraDepthTexture] 2D -SetTexture 1 [_MainTex] 2D -"!!ARBfp1.0 -OPTION ARB_precision_hint_fastest; -# 17 ALU, 2 TEX -PARAM c[6] = { program.local[0..3], - { 0.2199707, 0.70703125, 0.070983887, 1 }, - { 2 } }; -TEMP R0; -TEMP R1; -TEMP R2; -TEX R0, fragment.texcoord[0], texture[1], 2D; -TXP R1.x, fragment.texcoord[1], texture[0], 2D; -MAD R1.w, R1.x, c[0].z, c[0]; -RCP R2.x, R1.w; -DP3 R1.y, R0, c[4]; -ADD R2.x, R2, -fragment.texcoord[1].z; -MUL_SAT R2.w, R2.x, c[2].x; -MUL R1.y, R1, c[3].x; -ADD_SAT R1.y, R1, -c[4].w; -ADD R1.xyz, R1.y, c[1]; -MOV R1.w, c[1]; -MUL R1, R1, c[3].x; -MOV R2.xyz, fragment.color.primary; -MUL R2.w, fragment.color.primary, R2; -MUL R0, R2, R0; -MUL R0, R0, R1; -MUL result.color, R0, c[5].x; -END -# 17 instructions, 3 R-regs -" -} - -SubProgram "d3d9 " { -Keywords { "SOFTPARTICLES_ON" } -Vector 0 [_ZBufferParams] -Vector 1 [_TintColor] -Float 2 [_InvFade] -Float 3 [_Lum] -SetTexture 0 [_CameraDepthTexture] 2D -SetTexture 1 [_MainTex] 2D -"ps_2_0 -; 16 ALU, 2 TEX -dcl_2d s0 -dcl_2d s1 -def c4, 0.21997070, 0.70703125, 0.07098389, -1.00000000 -def c5, 2.00000000, 0, 0, 0 -dcl v0 -dcl t0.xy -dcl t1 -texldp r0, t1, s0 -texld r1, t0, s1 -mad r0.x, r0, c0.z, c0.w -dp3_pp r2.x, r1, c4 -rcp r0.x, r0.x -mul r2.x, r2, c3 -add r0.x, r0, -t1.z -mul_sat r0.x, r0, c2 -add_sat r2.x, r2, c4.w -mov_pp r2.w, c1 -add_pp r2.xyz, r2.x, c1 -mul_pp r2, r2, c3.x -mov_pp r3.xyz, v0 -mul_pp r3.w, v0, r0.x -mul r0, r3, r1 -mul r0, r0, r2 -mul r0, r0, c5.x -mov_pp oC0, r0 -" -} - -SubProgram "d3d11 " { -Keywords { "SOFTPARTICLES_ON" } -ConstBuffer "$Globals" 64 // 56 used size, 5 vars -Vector 16 [_TintColor] 4 -Float 48 [_InvFade] -Float 52 [_Lum] -ConstBuffer "UnityPerCamera" 128 // 128 used size, 8 vars -Vector 112 [_ZBufferParams] 4 -BindCB "$Globals" 0 -BindCB "UnityPerCamera" 1 -SetTexture 0 [_CameraDepthTexture] 2D 1 -SetTexture 1 [_MainTex] 2D 0 -// 18 instructions, 2 temp regs, 0 temp arrays: -// ALU 12 float, 0 int, 0 uint -// TEX 2 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"ps_4_0 -eefiecedpgjphnhopoaiafjcapaeikofldhlojbnabaaaaaamaadaaaaadaaaaaa -cmaaaaaaliaaaaaaomaaaaaaejfdeheoieaaaaaaaeaaaaaaaiaaaaaagiaaaaaa -aaaaaaaaabaaaaaaadaaaaaaaaaaaaaaapaaaaaaheaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaapapaaaahkaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaa -adadaaaahkaaaaaaabaaaaaaaaaaaaaaadaaaaaaadaaaaaaapapaaaafdfgfpfa -gphdgjhegjgpgoaaedepemepfcaafeeffiedepepfceeaaklepfdeheocmaaaaaa -abaaaaaaaiaaaaaacaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapaaaaaa -fdfgfpfegbhcghgfheaaklklfdeieefcmmacaaaaeaaaaaaaldaaaaaafjaaaaae -egiocaaaaaaaaaaaaeaaaaaafjaaaaaeegiocaaaabaaaaaaaiaaaaaafkaaaaad -aagabaaaaaaaaaaafkaaaaadaagabaaaabaaaaaafibiaaaeaahabaaaaaaaaaaa -ffffaaaafibiaaaeaahabaaaabaaaaaaffffaaaagcbaaaadpcbabaaaabaaaaaa -gcbaaaaddcbabaaaacaaaaaagcbaaaadpcbabaaaadaaaaaagfaaaaadpccabaaa -aaaaaaaagiaaaaacacaaaaaaaoaaaaahdcaabaaaaaaaaaaaegbabaaaadaaaaaa -pgbpbaaaadaaaaaaefaaaaajpcaabaaaaaaaaaaaegaabaaaaaaaaaaaeghobaaa -aaaaaaaaaagabaaaabaaaaaadcaaaaalbcaabaaaaaaaaaaackiacaaaabaaaaaa -ahaaaaaaakaabaaaaaaaaaaadkiacaaaabaaaaaaahaaaaaaaoaaaaakbcaabaaa -aaaaaaaaaceaaaaaaaaaiadpaaaaiadpaaaaiadpaaaaiadpakaabaaaaaaaaaaa -aaaaaaaibcaabaaaaaaaaaaaakaabaaaaaaaaaaackbabaiaebaaaaaaadaaaaaa -dicaaaaibcaabaaaaaaaaaaaakaabaaaaaaaaaaaakiacaaaaaaaaaaaadaaaaaa -diaaaaahicaabaaaaaaaaaaaakaabaaaaaaaaaaadkbabaaaabaaaaaadgaaaaaf -hcaabaaaaaaaaaaaegbcbaaaabaaaaaaaaaaaaahpcaabaaaaaaaaaaaegaobaaa -aaaaaaaaegaobaaaaaaaaaaaefaaaaajpcaabaaaabaaaaaaegbabaaaacaaaaaa -eghobaaaabaaaaaaaagabaaaaaaaaaaadiaaaaahpcaabaaaaaaaaaaaegaobaaa -aaaaaaaaegaobaaaabaaaaaabaaaaaakbcaabaaaabaaaaaaegacbaaaabaaaaaa -aceaaaaakoehgbdopepndedphdgijbdnaaaaaaaadccaaaakbcaabaaaabaaaaaa -akaabaaaabaaaaaabkiacaaaaaaaaaaaadaaaaaaabeaaaaaaaaaialpaaaaaaai -hcaabaaaabaaaaaaagaabaaaabaaaaaaegiccaaaaaaaaaaaabaaaaaadiaaaaai -hcaabaaaabaaaaaaegacbaaaabaaaaaafgifcaaaaaaaaaaaadaaaaaadiaaaaaj -icaabaaaabaaaaaadkiacaaaaaaaaaaaabaaaaaabkiacaaaaaaaaaaaadaaaaaa -diaaaaahpccabaaaaaaaaaaaegaobaaaaaaaaaaaegaobaaaabaaaaaadoaaaaab -" -} - -SubProgram "gles " { -Keywords { "SOFTPARTICLES_ON" } -"!!GLES" -} - -SubProgram "glesdesktop " { -Keywords { "SOFTPARTICLES_ON" } -"!!GLES" -} - -SubProgram "flash " { -Keywords { "SOFTPARTICLES_ON" } -Vector 0 [_ZBufferParams] -Vector 1 [_TintColor] -Float 2 [_InvFade] -Float 3 [_Lum] -SetTexture 0 [_CameraDepthTexture] 2D -SetTexture 1 [_MainTex] 2D -"agal_ps -c4 1.0 0.003922 0.000015 0.0 -c5 0.219971 0.707031 0.070984 -1.0 -c6 2.0 0.0 0.0 0.0 -[bc] -aeaaaaaaaaaaapacabaaaaoeaeaaaaaaabaaaappaeaaaaaa div r0, v1, v1.w -ciaaaaaaaaaaapacaaaaaafeacaaaaaaaaaaaaaaafaababb tex r0, r0.xyyy, s0 <2d wrap linear point> -ciaaaaaaabaaapacaaaaaaoeaeaaaaaaabaaaaaaafaababb tex r1, v0, s1 <2d wrap linear point> -bdaaaaaaaaaaabacaaaaaaoeacaaaaaaaeaaaaoeabaaaaaa dp4 r0.x, r0, c4 -adaaaaaaaaaaabacaaaaaaaaacaaaaaaaaaaaakkabaaaaaa mul r0.x, r0.x, c0.z -abaaaaaaaaaaabacaaaaaaaaacaaaaaaaaaaaappabaaaaaa add r0.x, r0.x, c0.w -bcaaaaaaacaaabacabaaaakeacaaaaaaafaaaaoeabaaaaaa dp3 r2.x, r1.xyzz, c5 -afaaaaaaaaaaabacaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaa rcp r0.x, r0.x -adaaaaaaacaaabacacaaaaaaacaaaaaaadaaaaoeabaaaaaa mul r2.x, r2.x, c3 -acaaaaaaaaaaabacaaaaaaaaacaaaaaaabaaaakkaeaaaaaa sub r0.x, r0.x, v1.z -adaaaaaaaaaaabacaaaaaaaaacaaaaaaacaaaaoeabaaaaaa mul r0.x, r0.x, c2 -bgaaaaaaaaaaabacaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaa sat r0.x, r0.x -abaaaaaaacaaabacacaaaaaaacaaaaaaafaaaappabaaaaaa add r2.x, r2.x, c5.w -bgaaaaaaacaaabacacaaaaaaacaaaaaaaaaaaaaaaaaaaaaa sat r2.x, r2.x -aaaaaaaaacaaaiacabaaaaoeabaaaaaaaaaaaaaaaaaaaaaa mov r2.w, c1 -abaaaaaaacaaahacacaaaaaaacaaaaaaabaaaaoeabaaaaaa add r2.xyz, r2.x, c1 -adaaaaaaacaaapacacaaaaoeacaaaaaaadaaaaaaabaaaaaa mul r2, r2, c3.x -aaaaaaaaadaaahacahaaaaoeaeaaaaaaaaaaaaaaaaaaaaaa mov r3.xyz, v7 -adaaaaaaadaaaiacahaaaaoeaeaaaaaaaaaaaaaaacaaaaaa mul r3.w, v7, r0.x -adaaaaaaaaaaapacadaaaaoeacaaaaaaabaaaaoeacaaaaaa mul r0, r3, r1 -adaaaaaaaaaaapacaaaaaaoeacaaaaaaacaaaaoeacaaaaaa mul r0, r0, r2 -adaaaaaaaaaaapacaaaaaaoeacaaaaaaagaaaaaaabaaaaaa mul r0, r0, c6.x -aaaaaaaaaaaaapadaaaaaaoeacaaaaaaaaaaaaaaaaaaaaaa mov o0, r0 -" -} - -SubProgram "d3d11_9x " { -Keywords { "SOFTPARTICLES_ON" } -ConstBuffer "$Globals" 64 // 56 used size, 5 vars -Vector 16 [_TintColor] 4 -Float 48 [_InvFade] -Float 52 [_Lum] -ConstBuffer "UnityPerCamera" 128 // 128 used size, 8 vars -Vector 112 [_ZBufferParams] 4 -BindCB "$Globals" 0 -BindCB "UnityPerCamera" 1 -SetTexture 0 [_CameraDepthTexture] 2D 1 -SetTexture 1 [_MainTex] 2D 0 -// 18 instructions, 2 temp regs, 0 temp arrays: -// ALU 12 float, 0 int, 0 uint -// TEX 2 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"ps_4_0_level_9_1 -eefiecedfjlokpmfpfipmpcighlfbbnfohnehdeiabaaaaaakmafaaaaaeaaaaaa -daaaaaaabiacaaaaomaeaaaahiafaaaaebgpgodjoaabaaaaoaabaaaaaaacpppp -jaabaaaafaaaaaaaadaacmaaaaaafaaaaaaafaaaacaaceaaaaaafaaaabaaaaaa -aaababaaaaaaabaaabaaaaaaaaaaaaaaaaaaadaaabaaabaaaaaaaaaaabaaahaa -abaaacaaaaaaaaaaaaacppppfbaaaaafadaaapkakoehgbdopepndedphdgijbdn -aaaaialpbpaaaaacaaaaaaiaaaaaaplabpaaaaacaaaaaaiaabaaadlabpaaaaac -aaaaaaiaacaaaplabpaaaaacaaaaaajaaaaiapkabpaaaaacaaaaaajaabaiapka -agaaaaacaaaaaiiaacaapplaafaaaaadaaaaadiaaaaappiaacaaoelaecaaaaad -aaaaapiaaaaaoeiaabaioekaecaaaaadabaacpiaabaaoelaaaaioekaaeaaaaae -aaaaabiaacaakkkaaaaaaaiaacaappkaagaaaaacaaaaabiaaaaaaaiaacaaaaad -aaaaabiaaaaaaaiaacaakklbafaaaaadaaaabbiaaaaaaaiaabaaaakaafaaaaad -aaaaciiaaaaaaaiaaaaapplaabaaaaacaaaaahiaaaaaoelaacaaaaadaaaaapia -aaaaoeiaaaaaoeiaafaaaaadaaaaapiaabaaoeiaaaaaoeiaaiaaaaadabaacbia -abaaoeiaadaaoekaabaaaaacabaaaciaabaaffkaaeaaaaaeabaabbiaabaaaaia -abaaffiaadaappkaacaaaaadacaachiaabaaaaiaaaaaoekaafaaaaadacaachia -acaaoeiaabaaffkaafaaaaadacaaciiaabaaffiaaaaappkaafaaaaadaaaacpia -aaaaoeiaacaaoeiaabaaaaacaaaicpiaaaaaoeiappppaaaafdeieefcmmacaaaa -eaaaaaaaldaaaaaafjaaaaaeegiocaaaaaaaaaaaaeaaaaaafjaaaaaeegiocaaa -abaaaaaaaiaaaaaafkaaaaadaagabaaaaaaaaaaafkaaaaadaagabaaaabaaaaaa -fibiaaaeaahabaaaaaaaaaaaffffaaaafibiaaaeaahabaaaabaaaaaaffffaaaa -gcbaaaadpcbabaaaabaaaaaagcbaaaaddcbabaaaacaaaaaagcbaaaadpcbabaaa -adaaaaaagfaaaaadpccabaaaaaaaaaaagiaaaaacacaaaaaaaoaaaaahdcaabaaa -aaaaaaaaegbabaaaadaaaaaapgbpbaaaadaaaaaaefaaaaajpcaabaaaaaaaaaaa -egaabaaaaaaaaaaaeghobaaaaaaaaaaaaagabaaaabaaaaaadcaaaaalbcaabaaa -aaaaaaaackiacaaaabaaaaaaahaaaaaaakaabaaaaaaaaaaadkiacaaaabaaaaaa -ahaaaaaaaoaaaaakbcaabaaaaaaaaaaaaceaaaaaaaaaiadpaaaaiadpaaaaiadp -aaaaiadpakaabaaaaaaaaaaaaaaaaaaibcaabaaaaaaaaaaaakaabaaaaaaaaaaa -ckbabaiaebaaaaaaadaaaaaadicaaaaibcaabaaaaaaaaaaaakaabaaaaaaaaaaa -akiacaaaaaaaaaaaadaaaaaadiaaaaahicaabaaaaaaaaaaaakaabaaaaaaaaaaa -dkbabaaaabaaaaaadgaaaaafhcaabaaaaaaaaaaaegbcbaaaabaaaaaaaaaaaaah -pcaabaaaaaaaaaaaegaobaaaaaaaaaaaegaobaaaaaaaaaaaefaaaaajpcaabaaa -abaaaaaaegbabaaaacaaaaaaeghobaaaabaaaaaaaagabaaaaaaaaaaadiaaaaah -pcaabaaaaaaaaaaaegaobaaaaaaaaaaaegaobaaaabaaaaaabaaaaaakbcaabaaa -abaaaaaaegacbaaaabaaaaaaaceaaaaakoehgbdopepndedphdgijbdnaaaaaaaa -dccaaaakbcaabaaaabaaaaaaakaabaaaabaaaaaabkiacaaaaaaaaaaaadaaaaaa -abeaaaaaaaaaialpaaaaaaaihcaabaaaabaaaaaaagaabaaaabaaaaaaegiccaaa -aaaaaaaaabaaaaaadiaaaaaihcaabaaaabaaaaaaegacbaaaabaaaaaafgifcaaa -aaaaaaaaadaaaaaadiaaaaajicaabaaaabaaaaaadkiacaaaaaaaaaaaabaaaaaa -bkiacaaaaaaaaaaaadaaaaaadiaaaaahpccabaaaaaaaaaaaegaobaaaaaaaaaaa -egaobaaaabaaaaaadoaaaaabejfdeheoieaaaaaaaeaaaaaaaiaaaaaagiaaaaaa -aaaaaaaaabaaaaaaadaaaaaaaaaaaaaaapaaaaaaheaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaapapaaaahkaaaaaaaaaaaaaaaaaaaaaaadaaaaaaacaaaaaa -adadaaaahkaaaaaaabaaaaaaaaaaaaaaadaaaaaaadaaaaaaapapaaaafdfgfpfa -gphdgjhegjgpgoaaedepemepfcaafeeffiedepepfceeaaklepfdeheocmaaaaaa -abaaaaaaaiaaaaaacaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapaaaaaa -fdfgfpfegbhcghgfheaaklkl" -} - -SubProgram "gles3 " { -Keywords { "SOFTPARTICLES_ON" } -"!!GLES3" -} - -} - -#LINE 99 - - } - } - - // ---- Dual texture cards - SubShader { - Pass { - SetTexture [_MainTex] { - constantColor [_TintColor] - combine constant * primary - } - SetTexture [_MainTex] { - combine texture * previous DOUBLE - } - } - } - - // ---- Single texture cards (does not do color tint) - SubShader - { - Pass - { - SetTexture [_MainTex] { - combine texture * primary - } - } - } - } -} diff --git a/BahaTurret/CMChaff.cs b/BahaTurret/CMChaff.cs deleted file mode 100644 index f32261df5..000000000 --- a/BahaTurret/CMChaff.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; - -namespace BahaTurret -{ - public class CMChaff : MonoBehaviour - { - KSPParticleEmitter pe; - - - const float drag = 5; - - Vector3d geoPos; - Vector3 velocity; - CelestialBody body; - - public void Emit(Vector3 position, Vector3 velocity) - { - transform.position = position; - this.velocity = velocity; - gameObject.SetActive(true); - } - - void OnEnable() - { - if(!pe) - { - pe = gameObject.GetComponentInChildren(); - } - - body = FlightGlobals.currentMainBody; - if(!body) - { - gameObject.SetActive(false); - return; - } - - StartCoroutine(LifeRoutine()); - } - - IEnumerator LifeRoutine() - { - geoPos = VectorUtils.WorldPositionToGeoCoords(transform.position, body); - - pe.EmitParticle(); - - float startTime = Time.time; - while(Time.time - startTime < pe.maxEnergy) - { - transform.position = body.GetWorldSurfacePosition(geoPos.x, geoPos.y, geoPos.z); - velocity += FlightGlobals.getGeeForceAtPosition(transform.position)*Time.fixedDeltaTime; - Vector3 dragForce = (0.008f) * drag * 0.5f * velocity.sqrMagnitude * (float) FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), FlightGlobals.getExternalTemperature(), body) * velocity.normalized; - velocity -= (dragForce)*Time.fixedDeltaTime; - transform.position += velocity * Time.fixedDeltaTime; - geoPos = VectorUtils.WorldPositionToGeoCoords(transform.position, body); - yield return new WaitForFixedUpdate(); - } - - gameObject.SetActive(false); - } - } -} - diff --git a/BahaTurret/CMDropper.cs b/BahaTurret/CMDropper.cs deleted file mode 100644 index d0d22c66b..000000000 --- a/BahaTurret/CMDropper.cs +++ /dev/null @@ -1,283 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; - -namespace BahaTurret -{ - public class CMDropper : PartModule - { - public static ObjectPool flarePool; - public static ObjectPool chaffPool; - public static ObjectPool smokePool; - - public enum CountermeasureTypes{Flare, Chaff, Smoke} - public CountermeasureTypes cmType = CountermeasureTypes.Flare; - [KSPField] - public string countermeasureType = "flare"; - - [KSPField] - public float ejectVelocity = 30; - - [KSPField] - public string ejectTransformName; - Transform ejectTransform; - - [KSPField] - public string effectsTransformName = string.Empty; - Transform effectsTransform; - - - AudioSource audioSource; - AudioClip cmSound; - AudioClip smokePoofSound; - - string resourceName; - - VesselChaffInfo vci; - - [KSPAction("Fire Countermeasure")] - public void AGDropCM(KSPActionParam param) - { - DropCM(); - } - - [KSPEvent(guiActive = true, guiName = "Fire Countermeasure", active = true)] - public void DropCM() - { - switch(cmType) - { - case CountermeasureTypes.Flare: - DropFlare(); - break; - case CountermeasureTypes.Chaff: - DropChaff(); - break; - case CountermeasureTypes.Smoke: - PopSmoke(); - break; - } - - - } - - public override void OnStart (PartModule.StartState state) - { - if(HighLogic.LoadedSceneIsFlight) - { - SetupCM(); - - ejectTransform = part.FindModelTransform(ejectTransformName); - - if(effectsTransformName != string.Empty) - { - effectsTransform = part.FindModelTransform(effectsTransformName); - } - - part.force_activate(); - - audioSource = gameObject.AddComponent(); - audioSource.minDistance = 1; - audioSource.maxDistance = 1000; - audioSource.spatialBlend = 1; - - UpdateVolume(); - BDArmorySettings.OnVolumeChange += UpdateVolume; - } - } - - void UpdateVolume() - { - if(audioSource) - { - audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - } - } - - void OnDestroy() - { - BDArmorySettings.OnVolumeChange -= UpdateVolume; - } - - public override void OnUpdate () - { - if(audioSource) - { - if(vessel.isActiveVessel) - { - audioSource.dopplerLevel = 0; - } - else - { - audioSource.dopplerLevel = 1; - } - } - } - - void FireParticleEffects() - { - if(effectsTransform) - { - foreach(var pe in effectsTransform.gameObject.GetComponentsInChildren()) - { - pe.Emit(); - } - } - } - - - PartResource GetCMResource() - { - foreach(var res in part.Resources.list) - { - if(res.resourceName == resourceName) return res; - } - - return null; - } - - void SetupCM() - { - countermeasureType = countermeasureType.ToLower(); - switch(countermeasureType) - { - case "flare": - cmType = CountermeasureTypes.Flare; - cmSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/flareSound"); - if(!flarePool) - { - SetupFlarePool(); - } - resourceName = "CMFlare"; - break; - case "chaff": - cmType = CountermeasureTypes.Chaff; - cmSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/smokeEject"); - resourceName = "CMChaff"; - vci = vessel.GetComponent(); - if(!vci) - { - vci = vessel.gameObject.AddComponent(); - } - if(!chaffPool) - { - SetupChaffPool(); - } - break; - case "smoke": - cmType = CountermeasureTypes.Smoke; - cmSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/smokeEject"); - smokePoofSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/smokePoof"); - resourceName = "CMSmoke"; - if(smokePool == null) - { - SetupSmokePool(); - } - break; - } - } - - void DropFlare() - { - PartResource cmResource = GetCMResource(); - if(cmResource && cmResource.amount >= 1) - { - cmResource.amount--; - audioSource.pitch = UnityEngine.Random.Range(0.9f, 1.1f); - audioSource.PlayOneShot(cmSound); - - GameObject cm = flarePool.GetPooledObject(); - cm.transform.position = transform.position; - CMFlare cmf = cm.GetComponent(); - cmf.startVelocity = part.rb.velocity + (ejectVelocity*transform.up) + (UnityEngine.Random.Range(-3f,3f) * transform.forward) + (UnityEngine.Random.Range(-3f,3f) * transform.right); - cmf.sourceVessel = vessel; - - cm.SetActive(true); - - FireParticleEffects(); - } - } - - void DropChaff() - { - PartResource cmResource = GetCMResource(); - if(cmResource && cmResource.amount >= 1) - { - cmResource.amount--; - audioSource.pitch = UnityEngine.Random.Range(0.9f, 1.1f); - audioSource.PlayOneShot(cmSound); - - if(!vci) - { - vci = vessel.gameObject.AddComponent(); - } - vci.Chaff(); - - GameObject cm = chaffPool.GetPooledObject(); - CMChaff chaff = cm.GetComponent(); - chaff.Emit(ejectTransform.position, ejectVelocity * ejectTransform.forward); - - FireParticleEffects(); - } - } - - void PopSmoke() - { - PartResource smokeResource = GetCMResource(); - if(smokeResource.amount >= 1) - { - smokeResource.amount--; - audioSource.pitch = UnityEngine.Random.Range(0.9f, 1.1f); - audioSource.PlayOneShot(cmSound); - - StartCoroutine(SmokeRoutine()); - - FireParticleEffects(); - } - } - - IEnumerator SmokeRoutine() - { - yield return new WaitForSeconds(0.2f); - GameObject smokeCMObject = smokePool.GetPooledObject(); - smokeCMObject.SetActive(true); - smokeCMObject.transform.position = ejectTransform.position + (10*ejectTransform.forward); - float longestLife = 0; - foreach(var emitter in smokeCMObject.GetComponentsInChildren()) - { - emitter.Emit(); - if(emitter.maxEnergy > longestLife) longestLife = emitter.maxEnergy; - } - audioSource.PlayOneShot(smokePoofSound); - yield return new WaitForSeconds(longestLife); - smokeCMObject.SetActive(false); - } - - void SetupFlarePool() - { - GameObject cm = (GameObject)Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/CMFlare/model")); - cm.SetActive(false); - cm.AddComponent(); - flarePool = ObjectPool.CreateObjectPool(cm, 10, true, true); - } - - void SetupSmokePool() - { - GameObject cm = (GameObject)Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/CMSmoke/cmSmokeModel")); - cm.SetActive(false); - cm.AddComponent(); - - smokePool = ObjectPool.CreateObjectPool(cm, 10, true, true); - } - - void SetupChaffPool() - { - GameObject cm = (GameObject)Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/CMChaff/model")); - cm.SetActive(false); - cm.AddComponent(); - - chaffPool = ObjectPool.CreateObjectPool(cm, 10, true, true); - } - - } -} - diff --git a/BahaTurret/CMFlare.cs b/BahaTurret/CMFlare.cs deleted file mode 100644 index 99ce699e2..000000000 --- a/BahaTurret/CMFlare.cs +++ /dev/null @@ -1,223 +0,0 @@ -using System; -using UnityEngine; -using System.Collections.Generic; - -namespace BahaTurret -{ - public class CMFlare : MonoBehaviour - { - public Vessel sourceVessel; - Vector3 relativePos; - - List pEmitters;// = new List(); - List gaplessEmitters;// = new List(); - - Light[] lights; - float startTime; - - public Vector3 startVelocity; - - public bool alive = true; - - Vector3 upDirection; - - public Vector3 velocity; - - public float thermal; //heat value - float minThermal = 0; - - float lifeTime = 6; - - void OnEnable() - { - - thermal = BDArmorySettings.FLARE_THERMAL * UnityEngine.Random.Range(0.45f, 1.25f); - minThermal = thermal * 0.35f; - - if(gaplessEmitters == null || pEmitters == null) - { - gaplessEmitters = new List(); - - pEmitters = new List(); - - foreach(var pe in gameObject.GetComponentsInChildren()) - { - if(pe.useWorldSpace) - { - BDAGaplessParticleEmitter gpe = pe.gameObject.AddComponent(); - gaplessEmitters.Add (gpe); - gpe.emit = true; - } - else - { - pEmitters.Add(pe); - pe.emit = true; - } - } - } - - foreach(var emitter in gaplessEmitters) - { - emitter.emit = true; - } - - foreach(var emitter in pEmitters) - { - emitter.emit = true; - } - - BDArmorySettings.numberOfParticleEmitters++; - - - if(lights == null) - { - lights = gameObject.GetComponentsInChildren(); - } - - foreach(var lgt in lights) - { - lgt.enabled = true; - } - - startTime = Time.time; - - //ksp force applier - //gameObject.AddComponent().drag = 0.4f; - - - BDArmorySettings.Flares.Add(this); - - if(sourceVessel!=null) - { - relativePos = transform.position-sourceVessel.transform.position; - } - - upDirection = VectorUtils.GetUpDirection(transform.position); - - velocity = startVelocity; - } - - void FixedUpdate() - { - if(!gameObject.activeInHierarchy) - { - return; - } - - if(velocity != Vector3.zero) - { - transform.rotation = Quaternion.LookRotation(velocity, upDirection); - } - - - //Particle effects - Vector3 downForce = Vector3.zero; - //downforce - - if(sourceVessel != null) - { - downForce = (Mathf.Clamp((float)sourceVessel.srfSpeed, 0.1f, 150)/150) * Mathf.Clamp01(20/Vector3.Distance(sourceVessel.transform.position,transform.position)) * 20 * -upDirection; - } - - //turbulence - foreach(var pe in gaplessEmitters) - { - if(pe && pe.pEmitter) - { - try - { - pe.pEmitter.worldVelocity = 2*ParticleTurbulence.flareTurbulence + downForce; - } - catch(NullReferenceException) - { - Debug.LogWarning("CMFlare NRE setting worldVelocity"); - } - - try - { - if(FlightGlobals.ActiveVessel && FlightGlobals.ActiveVessel.atmDensity <= 0) - { - pe.emit = false; - } - } - catch(NullReferenceException) - { - Debug.LogWarning ("CMFlare NRE checking density"); - } - } - } - // - - - //thermal decay - thermal = Mathf.MoveTowards(thermal, minThermal, ((BDArmorySettings.FLARE_THERMAL-minThermal)/lifeTime)*Time.fixedDeltaTime); - - - //floatingOrigin fix - if(sourceVessel!=null) - { - if(((transform.position-sourceVessel.transform.position)-relativePos).sqrMagnitude > 800 * 800) - { - transform.position = sourceVessel.transform.position+relativePos; - } - - relativePos = transform.position-sourceVessel.transform.position; - } - // - - - - - if(Time.time - startTime > lifeTime) //stop emitting after lifeTime seconds - { - alive = false; - BDArmorySettings.Flares.Remove(this); - - foreach(var pe in pEmitters) - { - pe.emit = false; - } - foreach(var gpe in gaplessEmitters) - { - gpe.emit = false; - } - foreach(var lgt in lights) - { - lgt.enabled = false; - } - } - - - - if(Time.time - startTime > lifeTime+11) //disable object after x seconds - { - BDArmorySettings.numberOfParticleEmitters--; - gameObject.SetActive(false); - return; - } - - - //physics - //atmospheric drag (stock) - float simSpeedSquared = velocity.sqrMagnitude; - Vector3 currPos = transform.position; - float mass = 0.001f; - float drag = 1f; - Vector3 dragForce = (0.008f * mass) * drag * 0.5f * simSpeedSquared * (float) FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody) * velocity.normalized; - - velocity -= (dragForce/mass)*Time.fixedDeltaTime; - // - - //gravity - if(FlightGlobals.RefFrameIsRotating) velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; - - transform.position += velocity * Time.fixedDeltaTime; - - } - - - - - } -} - diff --git a/BahaTurret/CMSmoke.cs b/BahaTurret/CMSmoke.cs deleted file mode 100644 index fe871493c..000000000 --- a/BahaTurret/CMSmoke.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections; -using UnityEngine; -namespace BahaTurret -{ - public class CMSmoke : MonoBehaviour - { - - void OnEnable() - { - StartCoroutine(SmokeRoutine()); - } - - IEnumerator SmokeRoutine() - { - yield return new WaitForSeconds(10); - - gameObject.SetActive(false); - } - - public static bool RaycastSmoke(Ray ray) - { - if(!CMDropper.smokePool) - { - return false; - } - - for(int i = 0; i < CMDropper.smokePool.size; i++) - { - Transform smokeTf = CMDropper.smokePool.GetPooledObject(i).transform; - if(smokeTf.gameObject.activeInHierarchy) - { - Plane smokePlane = new Plane((ray.origin-smokeTf.position).normalized, smokeTf.position); - float enter; - if(smokePlane.Raycast(ray, out enter)) - { - float dist = (ray.GetPoint(enter)-smokeTf.position).magnitude; - if(dist < 16) - { - return true; - } - } - } - } - - return false; - } - - } -} - diff --git a/BahaTurret/CameraBulletRenderer.cs b/BahaTurret/CameraBulletRenderer.cs deleted file mode 100644 index 2b67eb0f9..000000000 --- a/BahaTurret/CameraBulletRenderer.cs +++ /dev/null @@ -1,41 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; -namespace BahaTurret -{ - public class CameraBulletRenderer : MonoBehaviour - { - public float resizeFactor = 1; - Camera cam; - - void Awake() - { - cam = GetComponent(); - } - - void OnPreRender() - { - if(ModuleWeapon.bulletPool) - { - for(int i = 0; i < ModuleWeapon.bulletPool.size; i++) - { - if(ModuleWeapon.bulletPool.GetPooledObject(i).activeInHierarchy) - { - PooledBullet pBullet = ModuleWeapon.bulletPool.GetPooledObject(i).GetComponent(); - pBullet.UpdateWidth(cam, resizeFactor); - } - - } - } - } - } -} - diff --git a/BahaTurret/ClusterBomb.cs b/BahaTurret/ClusterBomb.cs deleted file mode 100644 index 5c1144a89..000000000 --- a/BahaTurret/ClusterBomb.cs +++ /dev/null @@ -1,304 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class ClusterBomb : PartModule - { - - List submunitions; - List fairings; - MissileLauncher missileLauncher; - - bool deployed = false; - - [KSPField(isPersistant = false)] - public string subExplModelPath = "BDArmory/Models/explosion/explosion"; - - [KSPField(isPersistant = false)] - public string subExplSoundPath = "BDArmory/Sounds/subExplode"; - - - [KSPField(isPersistant = false)] - public float deployDelay = 2.5f; - - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Deploy Altitude"), - UI_FloatRange(minValue = 100f, maxValue = 1000f, stepIncrement = 10f, scene = UI_Scene.Editor)] - public float deployAltitude = 400; - - [KSPField(isPersistant = false)] - public float submunitionMaxSpeed = 10; - - - [KSPField(isPersistant = false)] - public bool swapCollidersOnDeploy = true; - - - - - public override void OnStart (PartModule.StartState state) - { - submunitions = new List(); - foreach(var sub in part.FindModelTransforms("submunition")) - { - submunitions.Add(sub.gameObject); - if(HighLogic.LoadedSceneIsFlight) - { - Rigidbody subRb = sub.gameObject.GetComponent(); - if(!subRb) - { - subRb = sub.gameObject.AddComponent(); - } - subRb.isKinematic = true; - subRb.mass = part.mass / part.FindModelTransforms("submunition").Length; - } - sub.gameObject.SetActive(false); - } - - fairings = new List(); - foreach(var fairing in part.FindModelTransforms("fairing")) - { - fairings.Add(fairing.gameObject); - if(HighLogic.LoadedSceneIsFlight) - { - Rigidbody fairingRb = fairing.gameObject.GetComponent(); - if(!fairingRb) - { - fairingRb = fairing.gameObject.AddComponent(); - } - fairingRb.isKinematic = true; - fairingRb.mass = 0.05f; - } - } - - missileLauncher = part.GetComponent(); - //missileLauncher.deployTime = deployDelay; - } - - public override void OnFixedUpdate () - { - if(missileLauncher!=null && missileLauncher.timeIndex > deployDelay && !deployed && AltitudeTrigger()) - { - DeploySubmunitions(); - } - } - - void DeploySubmunitions() - { - missileLauncher.sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/flare")); - FXMonger.Explode(part, transform.position+part.rb.velocity*Time.fixedDeltaTime, 0.1f); - - deployed = true; - if(swapCollidersOnDeploy) - { - foreach(var col in part.GetComponentsInChildren()) - { - col.enabled = !col.enabled; - } - } - - missileLauncher.sfAudioSource.priority = 999; - //missileLauncher.explosionSize = 3; - - foreach(var sub in submunitions) - { - sub.SetActive(true); - sub.transform.parent = null; - Vector3 direction = (sub.transform.position - part.transform.position).normalized; - Rigidbody subRB = sub.GetComponent(); - subRB.isKinematic = false; - subRB.velocity = part.rb.velocity + (UnityEngine.Random.Range(submunitionMaxSpeed/10, submunitionMaxSpeed) * direction); - - Submunition subScript = sub.AddComponent(); - subScript.enabled = true; - subScript.deployed = true; - subScript.sourceVessel = missileLauncher.sourceVessel; - subScript.blastForce = missileLauncher.blastPower; - subScript.blastHeat = missileLauncher.blastHeat; - subScript.blastRadius = missileLauncher.blastRadius; - subScript.subExplModelPath = subExplModelPath; - subScript.subExplSoundPath = subExplSoundPath; - sub.AddComponent(); - } - - foreach(var fairing in fairings) - { - Vector3 direction = (fairing.transform.position - part.transform.position).normalized; - Rigidbody fRB = fairing.GetComponent(); - fRB.isKinematic = false; - fRB.velocity = part.rb.velocity + ((submunitionMaxSpeed+2) * direction); - fairing.AddComponent(); - fairing.GetComponent().drag = 0.2f; - ClusterBombFairing fairingScript = fairing.AddComponent(); - fairingScript.deployed = true; - fairingScript.sourceVessel = vessel; - } - - part.explosionPotential = 0; - missileLauncher.hasFired = false; - - part.temperature = part.maxTemp + 10; - } - - - bool AltitudeTrigger() - { - double asl = vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass()); - double radarAlt = asl - vessel.terrainAltitude; - - return (radarAlt < deployAltitude || asl < deployAltitude) && vessel.verticalSpeed < 0; - } - - } - - - public class Submunition : MonoBehaviour - { - public bool deployed = false; - public float blastRadius; - public float blastForce; - public float blastHeat; - public string subExplModelPath; - public string subExplSoundPath; - public Vessel sourceVessel; - Vector3 currPosition; - Vector3 prevPosition; - Vector3 relativePos; - - float startTime; - - Rigidbody rb; - - void Start() - { - startTime = Time.time; - relativePos = transform.position-sourceVessel.transform.position; - currPosition = transform.position; - prevPosition = transform.position; - rb = GetComponent (); - } - - void FixedUpdate() - { - if(deployed) - { - if(Time.time-startTime > 30) - { - Destroy(gameObject); - return; - } - - //floatingOrigin fix - if(sourceVessel!=null && Vector3.Distance(transform.position-sourceVessel.transform.position, relativePos) > 800) - { - transform.position = sourceVessel.transform.position+relativePos + (rb.velocity * Time.fixedDeltaTime); - } - if(sourceVessel!=null) relativePos = transform.position-sourceVessel.transform.position; - // - - currPosition = transform.position; - float dist = (currPosition-prevPosition).magnitude; - Ray ray = new Ray(prevPosition, currPosition-prevPosition); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, dist, 557057)) - { - - Part hitPart = null; - try{ - hitPart = Part.FromGO(hit.rigidbody.gameObject); - }catch(NullReferenceException){} - - if(hitPart!=null) - { - float destroyChance = (rb.mass/hitPart.crashTolerance) * (rb.velocity-hit.rigidbody.velocity).magnitude * 8000; - if(BDArmorySettings.INSTAKILL) - { - destroyChance = 100; - } - Debug.Log ("Hit part: "+hitPart.name+", chance of destroy: "+destroyChance); - if(UnityEngine.Random.Range (0f,100f) (); - } - - void FixedUpdate() - { - if(deployed) - { - //floatingOrigin fix - if(sourceVessel!=null && Vector3.Distance(transform.position-sourceVessel.transform.position, relativePos) > 800) - { - transform.position = sourceVessel.transform.position+relativePos + (rb.velocity * Time.fixedDeltaTime); - } - if(sourceVessel!=null) relativePos = transform.position-sourceVessel.transform.position; - // - - currPosition = transform.position; - float dist = (currPosition-prevPosition).magnitude; - Ray ray = new Ray(prevPosition, currPosition-prevPosition); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, dist, 557057)) - { - GameObject.Destroy(gameObject); - } - else if(FlightGlobals.getAltitudeAtPos(currPosition)<=0) - { - GameObject.Destroy(gameObject); - } - else if(Time.time - startTime > 20) - { - GameObject.Destroy(gameObject); - } - } - } - - - - } -} - diff --git a/BahaTurret/DecoupledBooster.cs b/BahaTurret/DecoupledBooster.cs deleted file mode 100644 index 2d2f83120..000000000 --- a/BahaTurret/DecoupledBooster.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; - -namespace BahaTurret -{ - public class DecoupledBooster : MonoBehaviour - { - Rigidbody rb; - - IEnumerator SelfDestructRoutine() - { - foreach(var col in gameObject.GetComponentsInChildren()) - { - col.enabled = false; - } - yield return new WaitForSeconds(5); - Destroy(gameObject); - } - - public void DecoupleBooster(Vector3 startVelocity, float ejectSpeed) - { - transform.parent = null; - - rb = gameObject.AddComponent(); - gameObject.AddComponent(); - rb.velocity = startVelocity; - rb.velocity += ejectSpeed * transform.forward; - - StartCoroutine(SelfDestructRoutine()); - } - } -} - diff --git a/BahaTurret/ExplosionFX.cs b/BahaTurret/ExplosionFX.cs deleted file mode 100644 index 717427b39..000000000 --- a/BahaTurret/ExplosionFX.cs +++ /dev/null @@ -1,198 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class ExplosionFX : MonoBehaviour - { - KSPParticleEmitter[] pEmitters; - Light lightFX; - float startTime; - public AudioClip exSound; - public AudioSource audioSource; - float maxTime = 0; - - public float range; - - - void Start() - { - startTime = Time.time; - pEmitters = gameObject.GetComponentsInChildren(); - foreach(KSPParticleEmitter pe in pEmitters) - { - pe.emit = true; - - //if(pe.useWorldSpace) pe.force = (4.49f * FlightGlobals.getGeeForceAtPosition(transform.position)); - - if(pe.maxEnergy > maxTime) - { - maxTime = pe.maxEnergy; - } - } - lightFX = gameObject.AddComponent(); - lightFX.color = Misc.ParseColor255("255,238,184,255"); - lightFX.intensity = 8; - lightFX.range = range*3f; - lightFX.shadows = LightShadows.None; - - - - audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - - audioSource.PlayOneShot(exSound); - } - - - void FixedUpdate() - { - lightFX.intensity -= 12 * Time.fixedDeltaTime; - if(Time.time-startTime > 0.2f) - { - foreach(KSPParticleEmitter pe in pEmitters) - { - pe.emit = false; - } - - - } - - if(Time.time-startTime > maxTime) - { - GameObject.Destroy(gameObject); - } - } - - - - public static void CreateExplosion(Vector3 position, float radius, float power, float heat, Vessel sourceVessel, Vector3 direction, string explModelPath, string soundPath) - { - GameObject go; - AudioClip soundClip; - - go = GameDatabase.Instance.GetModel(explModelPath); - soundClip = GameDatabase.Instance.GetAudioClip(soundPath); - - - Quaternion rotation = Quaternion.LookRotation(VectorUtils.GetUpDirection(position)); - GameObject newExplosion = (GameObject)GameObject.Instantiate(go, position, rotation); - newExplosion.SetActive(true); - ExplosionFX eFx = newExplosion.AddComponent(); - eFx.exSound = soundClip; - eFx.audioSource = newExplosion.AddComponent(); - eFx.audioSource.minDistance = 200; - eFx.audioSource.maxDistance = 5500; - eFx.audioSource.spatialBlend = 1; - eFx.range = radius; - - if(power <= 5) - { - eFx.audioSource.minDistance = 4f; - eFx.audioSource.maxDistance = 3000; - eFx.audioSource.priority = 9999; - } - foreach(KSPParticleEmitter pe in newExplosion.GetComponentsInChildren()) - { - pe.emit = true; - } - - DoExplosionDamage(position, power, heat, radius, sourceVessel); - } - - public static float ExplosionHeatMultiplier = 4200; - public static float ExplosionImpulseMultiplier = 1.5f; - - public static void DoExplosionRay(Ray ray, float power, float heat, float maxDistance, ref List ignoreParts, ref List ignoreBldgs, Vessel sourceVessel = null) - { - RaycastHit rayHit; - if(Physics.Raycast(ray, out rayHit, maxDistance, 557057)) - { - float sqrDist = (rayHit.point - ray.origin).sqrMagnitude; - float sqrMaxDist = maxDistance * maxDistance; - float distanceFactor = Mathf.Clamp01((sqrMaxDist - sqrDist) / sqrMaxDist); - //parts - Part part = rayHit.collider.GetComponentInParent(); - if(part) - { - Vessel missileSource = null; - if(sourceVessel != null) - { - MissileLauncher ml = part.FindModuleImplementing(); - if(ml) - { - missileSource = ml.sourceVessel; - } - } - - - if(!ignoreParts.Contains(part) && part.physicalSignificance == Part.PhysicalSignificance.FULL && (!sourceVessel || sourceVessel != missileSource)) - { - ignoreParts.Add(part); - Rigidbody rb = part.GetComponent(); - if(rb) - { - rb.AddForceAtPosition(ray.direction * power * distanceFactor * ExplosionImpulseMultiplier, rayHit.point, ForceMode.Impulse); - } - if(heat < 0) - { - heat = power; - } - float heatDamage = (BDArmorySettings.DMG_MULTIPLIER/100) * ExplosionHeatMultiplier * heat * distanceFactor / part.crashTolerance; - float excessHeat = Mathf.Max(0, (float)(part.temperature + heatDamage - part.maxTemp)); - part.temperature += heatDamage; - if(BDArmorySettings.DRAW_DEBUG_LABELS) Debug.Log("====== Explosion ray hit part! Damage: " + heatDamage); - if(excessHeat > 0 && part.parent) - { - part.parent.temperature += excessHeat; - } - return; - } - } - - //buildings - DestructibleBuilding building = rayHit.collider.GetComponentInParent(); - if(building && !ignoreBldgs.Contains(building)) - { - ignoreBldgs.Add(building); - float damageToBuilding = (BDArmorySettings.DMG_MULTIPLIER/100) * ExplosionHeatMultiplier * 0.00645f * power * distanceFactor; - if(damageToBuilding > building.impactMomentumThreshold/10) building.AddDamage(damageToBuilding); - if(building.Damage > building.impactMomentumThreshold) building.Demolish(); - if(BDArmorySettings.DRAW_DEBUG_LABELS) Debug.Log("== Explosion hit destructible building! Damage: "+(damageToBuilding).ToString("0.00")+ ", total Damage: "+building.Damage); - } - } - } - - public static List ignoreParts = new List(); - public static List ignoreBuildings = new List(); - - public static void DoExplosionDamage(Vector3 position, float power, float heat, float maxDistance, Vessel sourceVessel) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) Debug.Log("======= Doing explosion sphere ========="); - ignoreParts.Clear(); - ignoreBuildings.Clear(); - foreach(var vessel in BDATargetManager.LoadedVessels) - { - if(vessel == null) continue; - if(vessel.loaded && !vessel.packed && (vessel.transform.position - position).magnitude < maxDistance * 4) - { - foreach(var part in vessel.parts) - { - if(!part) continue; - DoExplosionRay(new Ray(position, part.transform.TransformPoint(part.CoMOffset) - position), power, heat, maxDistance, ref ignoreParts, ref ignoreBuildings, sourceVessel); - } - } - } - - foreach(var bldg in BDATargetManager.LoadedBuildings) - { - if(bldg == null) continue; - if((bldg.transform.position - position).magnitude < maxDistance * 1000) - { - DoExplosionRay(new Ray(position, bldg.transform.position - position), power, heat, maxDistance, ref ignoreParts, ref ignoreBuildings); - } - } - } - } -} - diff --git a/BahaTurret/GPSTargetInfo.cs b/BahaTurret/GPSTargetInfo.cs deleted file mode 100644 index efb49a3b6..000000000 --- a/BahaTurret/GPSTargetInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; - -namespace BahaTurret -{ - public struct GPSTargetInfo - { - public Vector3d gpsCoordinates; - public string name; - public Vector3d worldPos - { - get - { - if(!FlightGlobals.currentMainBody) return Vector3d.zero; - return VectorUtils.GetWorldSurfacePostion(gpsCoordinates, FlightGlobals.currentMainBody); - } - } - - public GPSTargetInfo(Vector3d coords, string name) - { - gpsCoordinates = coords; - this.name = name; - } - - - public bool EqualsTarget(GPSTargetInfo other) - { - return (name == other.name) && (gpsCoordinates == other.gpsCoordinates); - } - } -} - diff --git a/BahaTurret/GrayscaleEffectShader.shader b/BahaTurret/GrayscaleEffectShader.shader deleted file mode 100644 index 7be461a69..000000000 --- a/BahaTurret/GrayscaleEffectShader.shader +++ /dev/null @@ -1,727 +0,0 @@ -Shader "Grayscale Effect" { -Properties { - _MainTex ("Base (RGB)", 2D) = "white" {} - _RampTex ("Base (RGB)", 2D) = "grayscaleRamp" {} - _MinClamp("_MinClamp", Range(0.01,5) ) = 1 -} - -SubShader { - Pass { - ZTest Always Cull Off ZWrite On - -Program "vp" { -// Vertex combos: 1 -// opengl - ALU: 8 to 8 -// d3d9 - ALU: 8 to 8 -// d3d11 - ALU: 2 to 2, TEX: 0 to 0, FLOW: 1 to 1 -// d3d11_9x - ALU: 2 to 2, TEX: 0 to 0, FLOW: 1 to 1 -SubProgram "opengl " { -Keywords { } -Bind "vertex" Vertex -Bind "texcoord" TexCoord0 -"!!ARBvp1.0 -# 8 ALU -PARAM c[9] = { { 0 }, - state.matrix.mvp, - state.matrix.texture[0] }; -TEMP R0; -MOV R0.zw, c[0].x; -MOV R0.xy, vertex.texcoord[0]; -DP4 result.texcoord[0].y, R0, c[6]; -DP4 result.texcoord[0].x, R0, c[5]; -DP4 result.position.w, vertex.position, c[4]; -DP4 result.position.z, vertex.position, c[3]; -DP4 result.position.y, vertex.position, c[2]; -DP4 result.position.x, vertex.position, c[1]; -END -# 8 instructions, 1 R-regs -" -} - -SubProgram "d3d9 " { -Keywords { } -Bind "vertex" Vertex -Bind "texcoord" TexCoord0 -Matrix 0 [glstate_matrix_mvp] -Matrix 4 [glstate_matrix_texture0] -"vs_2_0 -; 8 ALU -def c8, 0.00000000, 0, 0, 0 -dcl_position0 v0 -dcl_texcoord0 v1 -mov r0.zw, c8.x -mov r0.xy, v1 -dp4 oT0.y, r0, c5 -dp4 oT0.x, r0, c4 -dp4 oPos.w, v0, c3 -dp4 oPos.z, v0, c2 -dp4 oPos.y, v0, c1 -dp4 oPos.x, v0, c0 -" -} - -SubProgram "d3d11 " { -Keywords { } -Bind "vertex" Vertex -Bind "texcoord" TexCoord0 -ConstBuffer "UnityPerDraw" 336 // 64 used size, 6 vars -Matrix 0 [glstate_matrix_mvp] 4 -ConstBuffer "UnityPerDrawTexMatrices" 768 // 576 used size, 5 vars -Matrix 512 [glstate_matrix_texture0] 4 -BindCB "UnityPerDraw" 0 -BindCB "UnityPerDrawTexMatrices" 1 -// 7 instructions, 1 temp regs, 0 temp arrays: -// ALU 2 float, 0 int, 0 uint -// TEX 0 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"vs_4_0 -eefiecedeedelkdobbmimfefjdhgabnhlefmpcmlabaaaaaaciacaaaaadaaaaaa -cmaaaaaaiaaaaaaaniaaaaaaejfdeheoemaaaaaaacaaaaaaaiaaaaaadiaaaaaa -aaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapapaaaaebaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaadadaaaafaepfdejfeejepeoaafeeffiedepepfceeaaklkl -epfdeheofaaaaaaaacaaaaaaaiaaaaaadiaaaaaaaaaaaaaaabaaaaaaadaaaaaa -aaaaaaaaapaaaaaaeeaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaadamaaaa -fdfgfpfaepfdejfeejepeoaafeeffiedepepfceeaaklklklfdeieefceiabaaaa -eaaaabaafcaaaaaafjaaaaaeegiocaaaaaaaaaaaaeaaaaaafjaaaaaeegiocaaa -abaaaaaaccaaaaaafpaaaaadpcbabaaaaaaaaaaafpaaaaaddcbabaaaabaaaaaa -ghaaaaaepccabaaaaaaaaaaaabaaaaaagfaaaaaddccabaaaabaaaaaagiaaaaac -abaaaaaadiaaaaaipcaabaaaaaaaaaaafgbfbaaaaaaaaaaaegiocaaaaaaaaaaa -abaaaaaadcaaaaakpcaabaaaaaaaaaaaegiocaaaaaaaaaaaaaaaaaaaagbabaaa -aaaaaaaaegaobaaaaaaaaaaadcaaaaakpcaabaaaaaaaaaaaegiocaaaaaaaaaaa -acaaaaaakgbkbaaaaaaaaaaaegaobaaaaaaaaaaadcaaaaakpccabaaaaaaaaaaa -egiocaaaaaaaaaaaadaaaaaapgbpbaaaaaaaaaaaegaobaaaaaaaaaaadiaaaaai -dcaabaaaaaaaaaaafgbfbaaaabaaaaaaegiacaaaabaaaaaacbaaaaaadcaaaaak -dccabaaaabaaaaaaegiacaaaabaaaaaacaaaaaaaagbabaaaabaaaaaaegaabaaa -aaaaaaaadoaaaaab" -} - -SubProgram "gles " { -Keywords { } -"!!GLES - - -#ifdef VERTEX - -varying mediump vec2 xlv_TEXCOORD0; -uniform highp mat4 glstate_matrix_texture0; -uniform highp mat4 glstate_matrix_mvp; -attribute vec4 _glesMultiTexCoord0; -attribute vec4 _glesVertex; -void main () -{ - vec2 tmpvar_1; - tmpvar_1 = _glesMultiTexCoord0.xy; - mediump vec2 tmpvar_2; - highp vec2 tmpvar_3; - highp vec4 tmpvar_4; - tmpvar_4.zw = vec2(0.0, 0.0); - tmpvar_4.x = tmpvar_1.x; - tmpvar_4.y = tmpvar_1.y; - tmpvar_3 = (glstate_matrix_texture0 * tmpvar_4).xy; - tmpvar_2 = tmpvar_3; - gl_Position = (glstate_matrix_mvp * _glesVertex); - xlv_TEXCOORD0 = tmpvar_2; -} - - - -#endif -#ifdef FRAGMENT - -varying mediump vec2 xlv_TEXCOORD0; -uniform mediump float _RampOffset; -uniform sampler2D _RampTex; -uniform sampler2D _MainTex; -void main () -{ - lowp vec4 xlat_var_output_1; - lowp float tmpvar_2; - tmpvar_2 = dot (texture2D (_MainTex, xlv_TEXCOORD0).xyz, vec3(0.22, 0.707, 0.071)); - mediump vec2 tmpvar_3; - tmpvar_3.y = 0.5; - tmpvar_3.x = (tmpvar_2 + _RampOffset); - xlat_var_output_1.xyz = texture2D (_RampTex, tmpvar_3).xyz; - xlat_var_output_1.w = 1.0; - gl_FragData[0] = xlat_var_output_1; -} - - - -#endif" -} - -SubProgram "glesdesktop " { -Keywords { } -"!!GLES - - -#ifdef VERTEX - -varying mediump vec2 xlv_TEXCOORD0; -uniform highp mat4 glstate_matrix_texture0; -uniform highp mat4 glstate_matrix_mvp; -attribute vec4 _glesMultiTexCoord0; -attribute vec4 _glesVertex; -void main () -{ - vec2 tmpvar_1; - tmpvar_1 = _glesMultiTexCoord0.xy; - mediump vec2 tmpvar_2; - highp vec2 tmpvar_3; - highp vec4 tmpvar_4; - tmpvar_4.zw = vec2(0.0, 0.0); - tmpvar_4.x = tmpvar_1.x; - tmpvar_4.y = tmpvar_1.y; - tmpvar_3 = (glstate_matrix_texture0 * tmpvar_4).xy; - tmpvar_2 = tmpvar_3; - gl_Position = (glstate_matrix_mvp * _glesVertex); - xlv_TEXCOORD0 = tmpvar_2; -} - - - -#endif -#ifdef FRAGMENT - -varying mediump vec2 xlv_TEXCOORD0; -uniform mediump float _RampOffset; -uniform sampler2D _RampTex; -uniform sampler2D _MainTex; -void main () -{ - lowp vec4 xlat_var_output_1; - lowp float tmpvar_2; - tmpvar_2 = dot (texture2D (_MainTex, xlv_TEXCOORD0).xyz, vec3(0.22, 0.707, 0.071)); - mediump vec2 tmpvar_3; - tmpvar_3.y = 0.5; - tmpvar_3.x = (tmpvar_2 + _RampOffset); - xlat_var_output_1.xyz = texture2D (_RampTex, tmpvar_3).xyz; - xlat_var_output_1.w = 1.0; - gl_FragData[0] = xlat_var_output_1; -} - - - -#endif" -} - -SubProgram "flash " { -Keywords { } -Bind "vertex" Vertex -Bind "texcoord" TexCoord0 -Matrix 0 [glstate_matrix_mvp] -Matrix 4 [glstate_matrix_texture0] -"agal_vs -c8 0.0 0.0 0.0 0.0 -[bc] -aaaaaaaaaaaaamacaiaaaaaaabaaaaaaaaaaaaaaaaaaaaaa mov r0.zw, c8.x -aaaaaaaaaaaaadacadaaaaoeaaaaaaaaaaaaaaaaaaaaaaaa mov r0.xy, a3 -bdaaaaaaaaaaacaeaaaaaaoeacaaaaaaafaaaaoeabaaaaaa dp4 v0.y, r0, c5 -bdaaaaaaaaaaabaeaaaaaaoeacaaaaaaaeaaaaoeabaaaaaa dp4 v0.x, r0, c4 -bdaaaaaaaaaaaiadaaaaaaoeaaaaaaaaadaaaaoeabaaaaaa dp4 o0.w, a0, c3 -bdaaaaaaaaaaaeadaaaaaaoeaaaaaaaaacaaaaoeabaaaaaa dp4 o0.z, a0, c2 -bdaaaaaaaaaaacadaaaaaaoeaaaaaaaaabaaaaoeabaaaaaa dp4 o0.y, a0, c1 -bdaaaaaaaaaaabadaaaaaaoeaaaaaaaaaaaaaaoeabaaaaaa dp4 o0.x, a0, c0 -aaaaaaaaaaaaamaeaaaaaaoeabaaaaaaaaaaaaaaaaaaaaaa mov v0.zw, c0 -" -} - -SubProgram "d3d11_9x " { -Keywords { } -Bind "vertex" Vertex -Bind "texcoord" TexCoord0 -ConstBuffer "UnityPerDraw" 336 // 64 used size, 6 vars -Matrix 0 [glstate_matrix_mvp] 4 -ConstBuffer "UnityPerDrawTexMatrices" 768 // 576 used size, 5 vars -Matrix 512 [glstate_matrix_texture0] 4 -BindCB "UnityPerDraw" 0 -BindCB "UnityPerDrawTexMatrices" 1 -// 7 instructions, 1 temp regs, 0 temp arrays: -// ALU 2 float, 0 int, 0 uint -// TEX 0 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"vs_4_0_level_9_1 -eefieceddhnbicbokkmhnihbiniipgnpnicndjjjabaaaaaaceadaaaaaeaaaaaa -daaaaaaaciabaaaahiacaaaammacaaaaebgpgodjpaaaaaaapaaaaaaaaaacpopp -laaaaaaaeaaaaaaaacaaceaaaaaadmaaaaaadmaaaaaaceaaabaadmaaaaaaaaaa -aeaaabaaaaaaaaaaabaacaaaacaaafaaaaaaaaaaaaaaaaaaaaacpoppbpaaaaac -afaaaaiaaaaaapjabpaaaaacafaaabiaabaaapjaafaaaaadaaaaadiaabaaffja -agaaoekaaeaaaaaeaaaaadoaafaaoekaabaaaajaaaaaoeiaafaaaaadaaaaapia -aaaaffjaacaaoekaaeaaaaaeaaaaapiaabaaoekaaaaaaajaaaaaoeiaaeaaaaae -aaaaapiaadaaoekaaaaakkjaaaaaoeiaaeaaaaaeaaaaapiaaeaaoekaaaaappja -aaaaoeiaaeaaaaaeaaaaadmaaaaappiaaaaaoekaaaaaoeiaabaaaaacaaaaamma -aaaaoeiappppaaaafdeieefceiabaaaaeaaaabaafcaaaaaafjaaaaaeegiocaaa -aaaaaaaaaeaaaaaafjaaaaaeegiocaaaabaaaaaaccaaaaaafpaaaaadpcbabaaa -aaaaaaaafpaaaaaddcbabaaaabaaaaaaghaaaaaepccabaaaaaaaaaaaabaaaaaa -gfaaaaaddccabaaaabaaaaaagiaaaaacabaaaaaadiaaaaaipcaabaaaaaaaaaaa -fgbfbaaaaaaaaaaaegiocaaaaaaaaaaaabaaaaaadcaaaaakpcaabaaaaaaaaaaa -egiocaaaaaaaaaaaaaaaaaaaagbabaaaaaaaaaaaegaobaaaaaaaaaaadcaaaaak -pcaabaaaaaaaaaaaegiocaaaaaaaaaaaacaaaaaakgbkbaaaaaaaaaaaegaobaaa -aaaaaaaadcaaaaakpccabaaaaaaaaaaaegiocaaaaaaaaaaaadaaaaaapgbpbaaa -aaaaaaaaegaobaaaaaaaaaaadiaaaaaidcaabaaaaaaaaaaafgbfbaaaabaaaaaa -egiacaaaabaaaaaacbaaaaaadcaaaaakdccabaaaabaaaaaaegiacaaaabaaaaaa -caaaaaaaagbabaaaabaaaaaaegaabaaaaaaaaaaadoaaaaabejfdeheoemaaaaaa -acaaaaaaaiaaaaaadiaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapapaaaa -ebaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaadadaaaafaepfdejfeejepeo -aafeeffiedepepfceeaaklklepfdeheofaaaaaaaacaaaaaaaiaaaaaadiaaaaaa -aaaaaaaaabaaaaaaadaaaaaaaaaaaaaaapaaaaaaeeaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaadamaaaafdfgfpfaepfdejfeejepeoaafeeffiedepepfcee -aaklklkl" -} - -SubProgram "gles3 " { -Keywords { } -"!!GLES3#version 300 es - - -#ifdef VERTEX - -#define gl_Vertex _glesVertex -in vec4 _glesVertex; -#define gl_MultiTexCoord0 _glesMultiTexCoord0 -in vec4 _glesMultiTexCoord0; - -#line 150 -struct v2f_vertex_lit { - highp vec2 uv; - lowp vec4 diff; - lowp vec4 spec; -}; -#line 186 -struct v2f_img { - highp vec4 pos; - mediump vec2 uv; -}; -#line 180 -struct appdata_img { - highp vec4 vertex; - mediump vec2 texcoord; -}; -uniform highp vec4 _Time; -uniform highp vec4 _SinTime; -#line 3 -uniform highp vec4 _CosTime; -uniform highp vec4 unity_DeltaTime; -uniform highp vec3 _WorldSpaceCameraPos; -uniform highp vec4 _ProjectionParams; -#line 7 -uniform highp vec4 _ScreenParams; -uniform highp vec4 _ZBufferParams; -uniform highp vec4 unity_CameraWorldClipPlanes[6]; -uniform highp vec4 _WorldSpaceLightPos0; -#line 11 -uniform highp vec4 _LightPositionRange; -uniform highp vec4 unity_4LightPosX0; -uniform highp vec4 unity_4LightPosY0; -uniform highp vec4 unity_4LightPosZ0; -#line 15 -uniform highp vec4 unity_4LightAtten0; -uniform highp vec4 unity_LightColor[4]; -uniform highp vec4 unity_LightPosition[4]; -uniform highp vec4 unity_LightAtten[4]; -#line 19 -uniform highp vec4 unity_SHAr; -uniform highp vec4 unity_SHAg; -uniform highp vec4 unity_SHAb; -uniform highp vec4 unity_SHBr; -#line 23 -uniform highp vec4 unity_SHBg; -uniform highp vec4 unity_SHBb; -uniform highp vec4 unity_SHC; -uniform highp vec3 unity_LightColor0; -uniform highp vec3 unity_LightColor1; -uniform highp vec3 unity_LightColor2; -uniform highp vec3 unity_LightColor3; -#line 27 -uniform highp vec4 unity_ShadowSplitSpheres[4]; -uniform highp vec4 unity_ShadowSplitSqRadii; -uniform highp vec4 unity_LightShadowBias; -uniform highp vec4 _LightSplitsNear; -#line 31 -uniform highp vec4 _LightSplitsFar; -uniform highp mat4 unity_World2Shadow[4]; -uniform highp vec4 _LightShadowData; -uniform highp vec4 unity_ShadowFadeCenterAndType; -#line 35 -uniform highp mat4 glstate_matrix_mvp; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_invtrans_modelview0; -uniform highp mat4 _Object2World; -#line 39 -uniform highp mat4 _World2Object; -uniform highp vec4 unity_Scale; -uniform highp mat4 glstate_matrix_transpose_modelview0; -uniform highp mat4 glstate_matrix_texture0; -#line 43 -uniform highp mat4 glstate_matrix_texture1; -uniform highp mat4 glstate_matrix_texture2; -uniform highp mat4 glstate_matrix_texture3; -uniform highp mat4 glstate_matrix_projection; -#line 47 -uniform highp vec4 glstate_lightmodel_ambient; -uniform highp mat4 unity_MatrixV; -uniform highp mat4 unity_MatrixVP; -uniform lowp vec4 unity_ColorSpaceGrey; -#line 76 -#line 81 -#line 86 -#line 90 -#line 95 -#line 119 -#line 136 -#line 157 -#line 165 -#line 192 -#line 205 -#line 214 -#line 219 -#line 228 -#line 233 -#line 242 -#line 259 -#line 264 -#line 290 -#line 298 -#line 302 -#line 306 -uniform sampler2D _MainTex; -uniform sampler2D _RampTex; -uniform mediump float _RampOffset; -uniform highp float _MinClamp; -#line 310 -#line 192 -highp vec2 MultiplyUV( in highp mat4 mat, in highp vec2 inUV ) { - highp vec4 temp = vec4( inUV.x, inUV.y, 0.0, 0.0); - temp = (mat * temp); - #line 196 - return temp.xy; -} -#line 198 -v2f_img vert_img( in appdata_img v ) { - #line 200 - v2f_img o; - o.pos = (glstate_matrix_mvp * v.vertex); - o.uv = MultiplyUV( glstate_matrix_texture0, v.texcoord); - return o; -} -out mediump vec2 xlv_TEXCOORD0; -void main() { - v2f_img xl_retval; - appdata_img xlt_v; - xlt_v.vertex = vec4(gl_Vertex); - xlt_v.texcoord = vec2(gl_MultiTexCoord0); - xl_retval = vert_img( xlt_v); - gl_Position = vec4(xl_retval.pos); - xlv_TEXCOORD0 = vec2(xl_retval.uv); -} - - -#endif -#ifdef FRAGMENT - -#define gl_FragData _glesFragData -layout(location = 0) out mediump vec4 _glesFragData[4]; - -#line 150 -struct v2f_vertex_lit { - highp vec2 uv; - lowp vec4 diff; - lowp vec4 spec; -}; -#line 186 -struct v2f_img { - highp vec4 pos; - mediump vec2 uv; -}; -#line 180 -struct appdata_img { - highp vec4 vertex; - mediump vec2 texcoord; -}; -uniform highp vec4 _Time; -uniform highp vec4 _SinTime; -#line 3 -uniform highp vec4 _CosTime; -uniform highp vec4 unity_DeltaTime; -uniform highp vec3 _WorldSpaceCameraPos; -uniform highp vec4 _ProjectionParams; -#line 7 -uniform highp vec4 _ScreenParams; -uniform highp vec4 _ZBufferParams; -uniform highp vec4 unity_CameraWorldClipPlanes[6]; -uniform highp vec4 _WorldSpaceLightPos0; -#line 11 -uniform highp vec4 _LightPositionRange; -uniform highp vec4 unity_4LightPosX0; -uniform highp vec4 unity_4LightPosY0; -uniform highp vec4 unity_4LightPosZ0; -#line 15 -uniform highp vec4 unity_4LightAtten0; -uniform highp vec4 unity_LightColor[4]; -uniform highp vec4 unity_LightPosition[4]; -uniform highp vec4 unity_LightAtten[4]; -#line 19 -uniform highp vec4 unity_SHAr; -uniform highp vec4 unity_SHAg; -uniform highp vec4 unity_SHAb; -uniform highp vec4 unity_SHBr; -#line 23 -uniform highp vec4 unity_SHBg; -uniform highp vec4 unity_SHBb; -uniform highp vec4 unity_SHC; -uniform highp vec3 unity_LightColor0; -uniform highp vec3 unity_LightColor1; -uniform highp vec3 unity_LightColor2; -uniform highp vec3 unity_LightColor3; -#line 27 -uniform highp vec4 unity_ShadowSplitSpheres[4]; -uniform highp vec4 unity_ShadowSplitSqRadii; -uniform highp vec4 unity_LightShadowBias; -uniform highp vec4 _LightSplitsNear; -#line 31 -uniform highp vec4 _LightSplitsFar; -uniform highp mat4 unity_World2Shadow[4]; -uniform highp vec4 _LightShadowData; -uniform highp vec4 unity_ShadowFadeCenterAndType; -#line 35 -uniform highp mat4 glstate_matrix_mvp; -uniform highp mat4 glstate_matrix_modelview0; -uniform highp mat4 glstate_matrix_invtrans_modelview0; -uniform highp mat4 _Object2World; -#line 39 -uniform highp mat4 _World2Object; -uniform highp vec4 unity_Scale; -uniform highp mat4 glstate_matrix_transpose_modelview0; -uniform highp mat4 glstate_matrix_texture0; -#line 43 -uniform highp mat4 glstate_matrix_texture1; -uniform highp mat4 glstate_matrix_texture2; -uniform highp mat4 glstate_matrix_texture3; -uniform highp mat4 glstate_matrix_projection; -#line 47 -uniform highp vec4 glstate_lightmodel_ambient; -uniform highp mat4 unity_MatrixV; -uniform highp mat4 unity_MatrixVP; -uniform lowp vec4 unity_ColorSpaceGrey; -#line 76 -#line 81 -#line 86 -#line 90 -#line 95 -#line 119 -#line 136 -#line 157 -#line 165 -#line 192 -#line 205 -#line 214 -#line 219 -#line 228 -#line 233 -#line 242 -#line 259 -#line 264 -#line 290 -#line 298 -#line 302 -#line 306 -uniform sampler2D _MainTex; -uniform sampler2D _RampTex; -uniform mediump float _RampOffset; -uniform highp float _MinClamp; -#line 310 -#line 172 -lowp float Luminance( in lowp vec3 c ) { - #line 174 - return dot( c, vec3( 0.22, 0.707, 0.071)); -} -#line 310 -lowp vec4 frag( in v2f_img i ) { - lowp vec4 original = texture( _MainTex, i.uv); - lowp float grayscale = Luminance( original.xyz); - #line 314 - mediump vec2 remap = vec2( (grayscale + _RampOffset), 0.5); - lowp vec4 xlat_var_output = texture( _RampTex, remap); - xlat_var_output.w = 1.0; - return xlat_var_output; -} -in mediump vec2 xlv_TEXCOORD0; -void main() { - lowp vec4 xl_retval; - v2f_img xlt_i; - xlt_i.pos = vec4(0.0); - xlt_i.uv = vec2(xlv_TEXCOORD0); - xl_retval = frag( xlt_i); - gl_FragData[0] = vec4(xl_retval); -} - - -#endif" -} - -} -Program "fp" { -// Fragment combos: 1 -// opengl - ALU: 6 to 6, TEX: 2 to 2 -// d3d9 - ALU: 5 to 5, TEX: 2 to 2 -// d3d11 - ALU: 2 to 2, TEX: 2 to 2, FLOW: 1 to 1 -// d3d11_9x - ALU: 2 to 2, TEX: 2 to 2, FLOW: 1 to 1 -SubProgram "opengl " { -Keywords { } -Float 0 [_RampOffset] -SetTexture 0 [_MainTex] 2D -SetTexture 1 [_RampTex] 2D -"!!ARBfp1.0 -# 6 ALU, 2 TEX -PARAM c[3] = { program.local[0], - { 1, 0.2199707, 0.70703125, 0.070983887 }, - { 0.5 } }; -TEMP R0; -TEX R0.xyz, fragment.texcoord[0], texture[0], 2D; -DP3 R0.x, R0, c[1].yzww; -MOV R0.y, c[2].x; -ADD R0.x, R0, c[0]; -MOV result.color.w, c[1].x; -TEX result.color.xyz, R0, texture[1], 2D; -END -# 6 instructions, 1 R-regs -" -} - -SubProgram "d3d9 " { -Keywords { } -Float 0 [_RampOffset] -SetTexture 0 [_MainTex] 2D -SetTexture 1 [_RampTex] 2D -"ps_2_0 -; 5 ALU, 2 TEX -dcl_2d s0 -dcl_2d s1 -def c1, 0.21997070, 0.70703125, 0.07098389, 0.50000000 -def c2, 1.00000000, 0, 0, 0 -dcl t0.xy -texld r0, t0, s0 -dp3_pp r0.x, r0, c1 -mov_pp r0.y, c1.w -add_pp r0.x, r0, c0 -texld r0, r0, s1 -mov_pp r0.w, c2.x -mov_pp oC0, r0 -" -} - -SubProgram "d3d11 " { -Keywords { } -ConstBuffer "$Globals" 32 // 20 used size, 3 vars -Float 16 [_RampOffset] -BindCB "$Globals" 0 -SetTexture 0 [_MainTex] 2D 0 -SetTexture 1 [_RampTex] 2D 1 -// 8 instructions, 1 temp regs, 0 temp arrays: -// ALU 2 float, 0 int, 0 uint -// TEX 2 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"ps_4_0 -eefiecedmippnbcgmpdicejlmddomlikfbjbfnjeabaaaaaaaaacaaaaadaaaaaa -cmaaaaaaieaaaaaaliaaaaaaejfdeheofaaaaaaaacaaaaaaaiaaaaaadiaaaaaa -aaaaaaaaabaaaaaaadaaaaaaaaaaaaaaapaaaaaaeeaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaabaaaaaaadadaaaafdfgfpfaepfdejfeejepeoaafeeffiedepepfcee -aaklklklepfdeheocmaaaaaaabaaaaaaaiaaaaaacaaaaaaaaaaaaaaaaaaaaaaa -adaaaaaaaaaaaaaaapaaaaaafdfgfpfegbhcghgfheaaklklfdeieefceaabaaaa -eaaaaaaafaaaaaaafjaaaaaeegiocaaaaaaaaaaaacaaaaaafkaaaaadaagabaaa -aaaaaaaafkaaaaadaagabaaaabaaaaaafibiaaaeaahabaaaaaaaaaaaffffaaaa -fibiaaaeaahabaaaabaaaaaaffffaaaagcbaaaaddcbabaaaabaaaaaagfaaaaad -pccabaaaaaaaaaaagiaaaaacabaaaaaaefaaaaajpcaabaaaaaaaaaaaegbabaaa -abaaaaaaeghobaaaaaaaaaaaaagabaaaaaaaaaaabaaaaaakbcaabaaaaaaaaaaa -egacbaaaaaaaaaaaaceaaaaakoehgbdopepndedphdgijbdnaaaaaaaaaaaaaaai -bcaabaaaaaaaaaaaakaabaaaaaaaaaaaakiacaaaaaaaaaaaabaaaaaadgaaaaaf -ccaabaaaaaaaaaaaabeaaaaaaaaaaadpefaaaaajpcaabaaaaaaaaaaaegaabaaa -aaaaaaaaeghobaaaabaaaaaaaagabaaaabaaaaaadgaaaaafhccabaaaaaaaaaaa -egacbaaaaaaaaaaadgaaaaaficcabaaaaaaaaaaaabeaaaaaaaaaiadpdoaaaaab -" -} - -SubProgram "gles " { -Keywords { } -"!!GLES" -} - -SubProgram "glesdesktop " { -Keywords { } -"!!GLES" -} - -SubProgram "flash " { -Keywords { } -Float 0 [_RampOffset] -SetTexture 0 [_MainTex] 2D -SetTexture 1 [_RampTex] 2D -"agal_ps -c1 0.219971 0.707031 0.070984 0.5 -c2 1.0 0.0 0.0 0.0 -[bc] -ciaaaaaaaaaaapacaaaaaaoeaeaaaaaaaaaaaaaaafaababb tex r0, v0, s0 <2d wrap linear point> -bcaaaaaaaaaaabacaaaaaakeacaaaaaaabaaaaoeabaaaaaa dp3 r0.x, r0.xyzz, c1 -aaaaaaaaaaaaacacabaaaappabaaaaaaaaaaaaaaaaaaaaaa mov r0.y, c1.w -abaaaaaaaaaaabacaaaaaaaaacaaaaaaaaaaaaoeabaaaaaa add r0.x, r0.x, c0 -ciaaaaaaaaaaapacaaaaaafeacaaaaaaabaaaaaaafaababb tex r0, r0.xyyy, s1 <2d wrap linear point> -aaaaaaaaaaaaaiacacaaaaaaabaaaaaaaaaaaaaaaaaaaaaa mov r0.w, c2.x -aaaaaaaaaaaaapadaaaaaaoeacaaaaaaaaaaaaaaaaaaaaaa mov o0, r0 -" -} - -SubProgram "d3d11_9x " { -Keywords { } -ConstBuffer "$Globals" 32 // 20 used size, 3 vars -Float 16 [_RampOffset] -BindCB "$Globals" 0 -SetTexture 0 [_MainTex] 2D 0 -SetTexture 1 [_RampTex] 2D 1 -// 8 instructions, 1 temp regs, 0 temp arrays: -// ALU 2 float, 0 int, 0 uint -// TEX 2 (0 load, 0 comp, 0 bias, 0 grad) -// FLOW 1 static, 0 dynamic -"ps_4_0_level_9_1 -eefiecedjppknlgcilgfochgkbaglmpemncoofigabaaaaaaaeadaaaaaeaaaaaa -daaaaaaadaabaaaahiacaaaanaacaaaaebgpgodjpiaaaaaapiaaaaaaaaacpppp -maaaaaaadiaaaaaaabaacmaaaaaadiaaaaaadiaaacaaceaaaaaadiaaaaaaaaaa -abababaaaaaaabaaabaaaaaaaaaaaaaaaaacppppfbaaaaafabaaapkakoehgbdo -pepndedphdgijbdnaaaaaadpfbaaaaafacaaapkaaaaaiadpaaaaaaaaaaaaaaaa -aaaaaaaabpaaaaacaaaaaaiaaaaacdlabpaaaaacaaaaaajaaaaiapkabpaaaaac -aaaaaajaabaiapkaecaaaaadaaaacpiaaaaaoelaaaaioekaaiaaaaadaaaacbia -aaaaoeiaabaaoekaacaaaaadaaaacbiaaaaaaaiaaaaaaakaabaaaaacaaaaccia -abaappkaecaaaaadaaaacpiaaaaaoeiaabaioekaabaaaaacaaaaciiaacaaaaka -abaaaaacaaaicpiaaaaaoeiappppaaaafdeieefceaabaaaaeaaaaaaafaaaaaaa -fjaaaaaeegiocaaaaaaaaaaaacaaaaaafkaaaaadaagabaaaaaaaaaaafkaaaaad -aagabaaaabaaaaaafibiaaaeaahabaaaaaaaaaaaffffaaaafibiaaaeaahabaaa -abaaaaaaffffaaaagcbaaaaddcbabaaaabaaaaaagfaaaaadpccabaaaaaaaaaaa -giaaaaacabaaaaaaefaaaaajpcaabaaaaaaaaaaaegbabaaaabaaaaaaeghobaaa -aaaaaaaaaagabaaaaaaaaaaabaaaaaakbcaabaaaaaaaaaaaegacbaaaaaaaaaaa -aceaaaaakoehgbdopepndedphdgijbdnaaaaaaaaaaaaaaaibcaabaaaaaaaaaaa -akaabaaaaaaaaaaaakiacaaaaaaaaaaaabaaaaaadgaaaaafccaabaaaaaaaaaaa -abeaaaaaaaaaaadpefaaaaajpcaabaaaaaaaaaaaegaabaaaaaaaaaaaeghobaaa -abaaaaaaaagabaaaabaaaaaadgaaaaafhccabaaaaaaaaaaaegacbaaaaaaaaaaa -dgaaaaaficcabaaaaaaaaaaaabeaaaaaaaaaiadpdoaaaaabejfdeheofaaaaaaa -acaaaaaaaiaaaaaadiaaaaaaaaaaaaaaabaaaaaaadaaaaaaaaaaaaaaapaaaaaa -eeaaaaaaaaaaaaaaaaaaaaaaadaaaaaaabaaaaaaadadaaaafdfgfpfaepfdejfe -ejepeoaafeeffiedepepfceeaaklklklepfdeheocmaaaaaaabaaaaaaaiaaaaaa -caaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaapaaaaaafdfgfpfegbhcghgf -heaaklkl" -} - -SubProgram "gles3 " { -Keywords { } -"!!GLES3" -} - -} - -#LINE 31 - - - } -} - -Fallback off - -} diff --git a/BahaTurret/IBDWeapon.cs b/BahaTurret/IBDWeapon.cs deleted file mode 100644 index 3159667a0..000000000 --- a/BahaTurret/IBDWeapon.cs +++ /dev/null @@ -1,24 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; -namespace BahaTurret -{ - public interface IBDWeapon - { - WeaponClasses GetWeaponClass(); - string GetShortName(); - string GetSubLabel(); - Part GetPart(); - } - - public enum WeaponClasses{Missile, Bomb, Gun, Rocket, DefenseLaser} -} - diff --git a/BahaTurret/KSPForceApplier.cs b/BahaTurret/KSPForceApplier.cs deleted file mode 100644 index c8dda98f3..000000000 --- a/BahaTurret/KSPForceApplier.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class KSPForceApplier : MonoBehaviour - { - public float drag = 0.02f; - - Rigidbody rb; - - void Start() - { - rb = GetComponent(); - } - - void FixedUpdate() - { - if(rb!=null && !rb.isKinematic) - { - rb.useGravity = false; - - //atmospheric drag (stock) - float simSpeedSquared = rb.velocity.sqrMagnitude; - Vector3 currPos = transform.position; - Vector3 dragForce = (0.008f * rb.mass) * drag * 0.5f * simSpeedSquared * (float) FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody) * rb.velocity.normalized; - - rb.velocity -= (dragForce/rb.mass)*Time.fixedDeltaTime; - // - - //gravity - if(FlightGlobals.RefFrameIsRotating) rb.velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; - } - } - } -} - diff --git a/BahaTurret/Misc.cs b/BahaTurret/Misc.cs deleted file mode 100644 index c28f3241e..000000000 --- a/BahaTurret/Misc.cs +++ /dev/null @@ -1,314 +0,0 @@ -using System; -using System.Reflection; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public static class Misc - { - - public static Color ParseColor255(string color) - { - Color outputColor = new Color(0,0,0,1); - - var strings = color.Split(","[0]); - for(int i = 0; i < 4; i++) - { - outputColor[i] = System.Single.Parse(strings[i])/255; - } - - return outputColor; - } - - public static AnimationState[] SetUpAnimation(string animationName, Part part) //Thanks Majiir! - { - var states = new List(); - foreach (var animation in part.FindModelAnimators(animationName)) - { - var animationState = animation[animationName]; - animationState.speed = 0; - animationState.enabled = true; - animationState.wrapMode = WrapMode.ClampForever; - animation.Blend(animationName); - states.Add(animationState); - } - return states.ToArray(); - } - - public static AnimationState SetUpSingleAnimation(string animationName, Part part) - { - var states = new List(); - - foreach (var animation in part.FindModelAnimators(animationName)) - { - var animationState = animation[animationName]; - animationState.speed = 0; - animationState.enabled = true; - animationState.wrapMode = WrapMode.ClampForever; - animation.Blend(animationName); - return animationState; - } - - return null; - } - - public static bool CheckMouseIsOnGui() - { - - if(!BDArmorySettings.GAME_UI_ENABLED) return false; - - if(!BDInputSettingsFields.WEAP_FIRE_KEY.inputString.Contains("mouse")) return false; - - - Vector3 inverseMousePos = new Vector3(Input.mousePosition.x, Screen.height-Input.mousePosition.y, 0); - Rect topGui = new Rect(0,0, Screen.width, 65); - - - if(topGui.Contains(inverseMousePos)) return true; - if(BDArmorySettings.toolbarGuiEnabled && BDArmorySettings.Instance.toolbarWindowRect.Contains(inverseMousePos)) return true; - if(ModuleTargetingCamera.windowIsOpen && ModuleTargetingCamera.camWindowRect.Contains(inverseMousePos)) return true; - if(BDArmorySettings.Instance.ActiveWeaponManager) - { - MissileFire wm = BDArmorySettings.Instance.ActiveWeaponManager; - - if(wm.vesselRadarData && wm.vesselRadarData.guiEnabled) - { - if(VesselRadarData.radarWindowRect.Contains(inverseMousePos)) return true; - if(wm.vesselRadarData.linkWindowOpen && wm.vesselRadarData.linkWindowRect.Contains(inverseMousePos)) return true; - } - if(wm.rwr && wm.rwr.rwrEnabled && RadarWarningReceiver.windowRect.Contains(inverseMousePos)) return true; - if(wm.wingCommander && wm.wingCommander.showGUI) - { - if(wm.wingCommander.guiWindowRect.Contains(inverseMousePos)) return true; - if(wm.wingCommander.showAGWindow && wm.wingCommander.agWindowRect.Contains(inverseMousePos)) return true; - } - - if(extraGUIRects != null) - { - for(int i = 0; i < extraGUIRects.Count; i++) - { - if(extraGUIRects[i].Contains(inverseMousePos)) return true; - } - } - } - - return false; - } - - public static List extraGUIRects; - - public static int RegisterGUIRect(Rect rect) - { - if(extraGUIRects == null) - { - extraGUIRects = new List(); - } - - int index = extraGUIRects.Count; - extraGUIRects.Add(rect); - return index; - } - - public static void UpdateGUIRect(Rect rect, int index) - { - if(extraGUIRects == null) - { - Debug.LogWarning("Trying to update a GUI rect for mouse position check, but Rect list is null."); - } - - extraGUIRects[index] = rect; - } - - public static bool MouseIsInRect(Rect rect) - { - Vector3 inverseMousePos = new Vector3(Input.mousePosition.x, Screen.height-Input.mousePosition.y, 0); - return rect.Contains(inverseMousePos); - } - - //Thanks FlowerChild - //refreshes part action window - public static void RefreshAssociatedWindows(Part part) - { - foreach ( UIPartActionWindow window in GameObject.FindObjectsOfType( typeof( UIPartActionWindow ) ) ) - { - if ( window.part == part ) - { - window.displayDirty = true; - } - } - } - - public static Vector3 ProjectOnPlane(Vector3 point, Vector3 planePoint, Vector3 planeNormal) - { - planeNormal = planeNormal.normalized; - - Plane plane = new Plane(planeNormal, planePoint); - float distance = plane.GetDistanceToPoint(point); - - return point - (distance*planeNormal); - } - - public static float SignedAngle(Vector3 fromDirection, Vector3 toDirection, Vector3 referenceRight) - { - float angle = Vector3.Angle(fromDirection, toDirection); - float sign = Mathf.Sign(Vector3.Dot(toDirection, referenceRight)); - float finalAngle = sign * angle; - return finalAngle; - } - /// - /// Parses the string to a curve. - /// Format: "key:pair,key:pair" - /// - /// The curve. - /// Curve string. - public static FloatCurve ParseCurve(string curveString) - { - string[] pairs = curveString.Split(new char[]{','}); - Keyframe[] keys = new Keyframe[pairs.Length]; - for(int p = 0; p < pairs.Length; p++) - { - string[] pair = pairs[p].Split(new char[]{':'}); - keys[p] = new Keyframe(float.Parse(pair[0]),float.Parse(pair[1])); - } - - FloatCurve curve = new FloatCurve(keys); - - return curve; - } - - public static bool CheckSightLine(Vector3 origin, Vector3 target, float maxDistance, float threshold, float startDistance) - { - float dist = maxDistance; - Ray ray = new Ray(origin, target-origin); - ray.origin += ray.direction*startDistance; - RaycastHit rayHit; - if(Physics.Raycast(ray, out rayHit, dist, 557057)) - { - if(Vector3.Distance(target, rayHit.point) < threshold) - { - return true; - } - else - { - return false; - } - } - - return false; - } - - public static bool CheckSightLineExactDistance(Vector3 origin, Vector3 target, float maxDistance, float threshold, float startDistance) - { - float dist = maxDistance; - Ray ray = new Ray(origin, target-origin); - ray.origin += ray.direction*startDistance; - RaycastHit rayHit; - if(Physics.Raycast(ray, out rayHit, dist, 557057)) - { - if(Vector3.Distance(target, rayHit.point) < threshold) - { - return true; - } - else - { - return false; - } - } - - return true; - } - - - - public static float[] ParseToFloatArray(string floatString) - { - string[] floatStrings = floatString.Split(new char[]{','}); - float[] floatArray = new float[floatStrings.Length]; - for(int i = 0; i < floatStrings.Length; i++) - { - floatArray[i] = float.Parse(floatStrings[i]); - } - - return floatArray; - } - - public static string FormattedGeoPos(Vector3d geoPos, bool altitude) - { - string finalString = string.Empty; - //lat - double lat = geoPos.x; - double latSign = Math.Sign(lat); - double latMajor = latSign * Math.Floor(Math.Abs(lat)); - double latMinor = 100 * (Math.Abs(lat) - Math.Abs(latMajor)); - string latString = latMajor.ToString("0") + " " + latMinor.ToString("0.000"); - finalString += "N:" + latString; - - - //longi - double longi = geoPos.y; - double longiSign = Math.Sign(longi); - double longiMajor = longiSign * Math.Floor(Math.Abs(longi)); - double longiMinor = 100 * (Math.Abs(longi) - Math.Abs(longiMajor)); - string longiString = longiMajor.ToString("0") + " " + longiMinor.ToString("0.000"); - finalString += " E:" + longiString; - - if(altitude) - { - finalString += " ASL:" + geoPos.z.ToString("0.000"); - } - - return finalString; - } - - public static string FormattedGeoPosShort(Vector3d geoPos, bool altitude) - { - string finalString = string.Empty; - //lat - double lat = geoPos.x; - double latSign = Math.Sign(lat); - double latMajor = latSign * Math.Floor(Math.Abs(lat)); - double latMinor = 100 * (Math.Abs(lat) - Math.Abs(latMajor)); - string latString = latMajor.ToString("0") + " " + latMinor.ToString("0"); - finalString += "N:" + latString; - - - //longi - double longi = geoPos.y; - double longiSign = Math.Sign(longi); - double longiMajor = longiSign * Math.Floor(Math.Abs(longi)); - double longiMinor = 100 * (Math.Abs(longi) - Math.Abs(longiMajor)); - string longiString = longiMajor.ToString("0") + " " + longiMinor.ToString("0"); - finalString += " E:" + longiString; - - if(altitude) - { - finalString += " ASL:" + geoPos.z.ToString("0"); - } - - return finalString; - } - - - - public static KeyBinding AGEnumToKeybinding(KSPActionGroup group) - { - string groupName = group.ToString(); - if(groupName.Contains("Custom")) - { - groupName = groupName.Substring(6); - int customNumber = int.Parse(groupName); - groupName = "CustomActionGroup" + customNumber; - } - else - { - return null; - } - - FieldInfo field = typeof(GameSettings).GetField(groupName); - return (KeyBinding)field.GetValue(null); - } - - } -} - diff --git a/BahaTurret/MissileFire.cs b/BahaTurret/MissileFire.cs deleted file mode 100644 index 09b964d48..000000000 --- a/BahaTurret/MissileFire.cs +++ /dev/null @@ -1,4398 +0,0 @@ -using System; -using System.Collections; -using System.Linq; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class MissileFire : PartModule - { - //weapons - private List weaponTypes = new List(); - public IBDWeapon[] weaponArray; - - [KSPField(guiActiveEditor = false, isPersistant = true, guiActive = false)] - public int weaponIndex = 0; - - ScreenMessage selectionMessage; - //ScreenMessage armedMessage; - string selectionText = ""; - Transform cameraTransform; - - float startTime; - - public bool hasLoadedRippleData = false; - float rippleTimer; - //[KSPField(isPersistant = true)] - public float rippleRPM - { - get - { - if(selectedWeapon != null) - { - return rippleDictionary[selectedWeapon.GetShortName()].rpm; - } - else - { - return 0; - } - } - set - { - if(selectedWeapon != null) - { - if(rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) - { - rippleDictionary[selectedWeapon.GetShortName()].rpm = value; - } - else - { - return; - } - } - else - { - return; - } - } - } - float triggerTimer = 0; - - int rippleGunCount = 0; - int _gunRippleIndex = 0; - public float gunRippleRpm = 0; - public int gunRippleIndex - { - get - { - return _gunRippleIndex; - } - set - { - _gunRippleIndex = value; - if(_gunRippleIndex >= rippleGunCount) - { - _gunRippleIndex = 0; - } - } - } - - - //ripple stuff - string rippleData = string.Empty; - Dictionary rippleDictionary; //weapon name, ripple option - - - //public float triggerHoldTime = 0.3f; - - //[KSPField(isPersistant = true)] - public bool rippleFire - { - get - { - if(selectedWeapon != null) - { - if(rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) - { - return rippleDictionary[selectedWeapon.GetShortName()].rippleFire; - } - else - { - //rippleDictionary.Add(selectedWeapon.GetShortName(), new RippleOption(false, 650)); - return false; - } - } - else - { - return false; - } - } - } - - public void ToggleRippleFire() - { - if(selectedWeapon != null) - { - RippleOption ro; - if(rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) - { - ro = rippleDictionary[selectedWeapon.GetShortName()]; - } - else - { - ro = new RippleOption(false, 650); //default to true ripple fire for guns, otherwise, false - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) - { - ro.rippleFire = currentGun.useRippleFire; - } - rippleDictionary.Add(selectedWeapon.GetShortName(), ro); - } - - ro.rippleFire = !ro.rippleFire; - - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) - { - foreach(ModuleWeapon w in vessel.FindPartModulesImplementing()) - { - if (w.GetShortName() == selectedWeapon.GetShortName()) - w.useRippleFire = ro.rippleFire; - } - } - } - } - - public void AGToggleRipple(KSPActionParam param) - { - ToggleRippleFire(); - } - - void ParseRippleOptions() - { - rippleDictionary = new Dictionary(); - Debug.Log("Parsing ripple options"); - if(!string.IsNullOrEmpty(rippleData)) - { - Debug.Log("Ripple data: " + rippleData); - try - { - foreach(string weapon in rippleData.Split(new char[]{';'})) - { - if(weapon == string.Empty) continue; - - string[] options = weapon.Split(new char[]{ ',' }); - string wpnName = options[0]; - bool rf = bool.Parse(options[1]); - float _rpm = float.Parse(options[2]); - RippleOption ro = new RippleOption(rf, _rpm); - rippleDictionary.Add(wpnName, ro); - } - } - catch(IndexOutOfRangeException) - { - Debug.Log("Ripple data was invalid."); - rippleData = string.Empty; - } - } - else - { - Debug.Log("Ripple data is empty."); - } - - if(vessel) - { - foreach(var rl in vessel.FindPartModulesImplementing()) - { - if(!rl) continue; - - if(!rippleDictionary.ContainsKey(rl.GetShortName())) - { - rippleDictionary.Add(rl.GetShortName(), new RippleOption(false, 650f)); - } - } - } - - hasLoadedRippleData = true; - } - - void SaveRippleOptions(ConfigNode node) - { - if(rippleDictionary != null) - { - rippleData = string.Empty; - foreach(var wpnName in rippleDictionary.Keys) - { - rippleData += wpnName + "," + rippleDictionary[wpnName].rippleFire.ToString() + "," + rippleDictionary[wpnName].rpm.ToString() + ";"; - } - - - node.SetValue("RippleData", rippleData, true); - } - Debug.Log("Saved ripple data: "+rippleData); - } - - public bool hasSingleFired = false; - - - // - - - //bomb aimer - Part bombPart = null; - Vector3 bombAimerPosition = Vector3.zero; - Texture2D bombAimerTexture = GameDatabase.Instance.GetTexture("BDArmory/Textures/grayCircle", false); - bool showBombAimer = false; - // - - - //targeting - private List loadedVessels = new List(); - float targetListTimer; - - - //rocket aimer handling - RocketLauncher currentRocket = null; - - - //sounds - AudioSource audioSource; - public AudioSource warningAudioSource; - AudioSource targetingAudioSource; - AudioClip clickSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/click"); - AudioClip warningSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/warning"); - AudioClip armOnSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/armOn"); - AudioClip armOffSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/armOff"); - AudioClip heatGrowlSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/heatGrowl"); - - //missile warning - public bool missileIsIncoming = false; - public float incomingMissileDistance = float.MaxValue; - public Vessel incomingMissileVessel; - - - //guard mode vars - float targetScanTimer = 0; - Vessel guardTarget = null; - public TargetInfo currentTarget; - TargetInfo overrideTarget; //used for setting target next guard scan for stuff like assisting teammates - float overrideTimer = 0; - public bool TargetOverride - { - get { return overrideTimer > 0; } - } - - //AIPilot - public BDModulePilotAI pilotAI = null; - public float timeBombReleased = 0; - - //targeting pods - public ModuleTargetingCamera mainTGP = null; - public List targetingPods = new List(); - - //radar - public List radars = new List(); - public VesselRadarData vesselRadarData; - - //jammers - public List jammers = new List(); - - //wingcommander - public ModuleWingCommander wingCommander; - - //RWR - private RadarWarningReceiver radarWarn = null; - public RadarWarningReceiver rwr - { - get - { - if(!radarWarn || radarWarn.vessel != vessel) - { - return null; - } - return radarWarn; - } - set - { - radarWarn = value; - } - } - - //GPS - public GPSTargetInfo designatedGPSInfo; - public Vector3d designatedGPSCoords - { - get - { - return designatedGPSInfo.gpsCoordinates; - } - } - - //Guard view scanning - float guardViewScanDirection = 1; - float guardViewScanRate = 200; - float currentGuardViewAngle = 0; - private Transform vrt; - public Transform viewReferenceTransform - { - get - { - if(vrt == null) - { - vrt = (new GameObject()).transform; - vrt.parent = transform; - vrt.localPosition = Vector3.zero; - vrt.rotation = Quaternion.LookRotation(-transform.forward, -vessel.ReferenceTransform.forward); - } - - return vrt; - } - } - - //weapon slaving - public bool slavingTurrets = false; - public Vector3 slavedPosition; - public Vector3 slavedVelocity; - public Vector3 slavedAcceleration; - - //current weapon ref - public MissileLauncher currentMissile = null; - //MissileLauncher currMiss; - /* - public MissileLauncher currentMissile - { - get - { - if(selectedWeapon != null && (selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb)) - { - if(currMiss!=null && currMiss.vessel==vessel && currMiss.GetShortName() == GetWeaponName(selectedWeapon)) - { - return currMiss; - } - else - { - currMiss = selectedWeapon.GetPart().FindModuleImplementing(); - return currMiss; - } - } - else - { - currMiss = null; - return null; - } - } - set - { - currMiss = value; - } - }*/ - - public ModuleWeapon currentGun - { - get - { - if(selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) - { - return selectedWeapon.GetPart().FindModuleImplementing(); - } - else - { - return null; - } - } - } - - - - //KSP fields and events - #region kspFields,events,actions - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Firing Interval"), - UI_FloatRange(minValue = 1f, maxValue = 60f, stepIncrement = 1f, scene = UI_Scene.All)] - public float targetScanInterval = 3; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Field of View"), - UI_FloatRange(minValue = 10f, maxValue = 360f, stepIncrement = 10f, scene = UI_Scene.All)] - public float guardAngle = 360; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "Visual Range"), - UI_FloatRange(minValue = 100f, maxValue = 5000, stepIncrement = 100f, scene = UI_Scene.All)] - public float guardRange = 5000; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "Guns Range"), - UI_FloatRange(minValue = 0f, maxValue = 10000f, stepIncrement = 10f, scene = UI_Scene.All)] - public float gunRange = 2000f; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "Missiles/Target"), - UI_FloatRange(minValue = 1f, maxValue = 6f, stepIncrement = 1f, scene = UI_Scene.All)] - public float maxMissilesOnTarget = 1; - - - public void ToggleGuardMode() - { - guardMode = !guardMode; - - if(!guardMode) - { - //disable turret firing and guard mode - foreach(var weapon in vessel.FindPartModulesImplementing()) - { - weapon.legacyTargetVessel = null; - weapon.autoFire = false; - weapon.aiControlled = false; - } - - } - } - - - - [KSPAction("Toggle Guard Mode")] - public void AGToggleGuardMode(KSPActionParam param) - { - ToggleGuardMode(); - } - - - [KSPField(isPersistant = true)] - public bool guardMode = false; - - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Target Type: "), - UI_Toggle(disabledText = "Vessels", enabledText = "Missiles")] - public bool targetMissiles = false; - - [KSPAction("Toggle Target Type")] - public void AGToggleTargetType(KSPActionParam param) - { - ToggleTargetType(); - } - - public void ToggleTargetType() - { - targetMissiles = !targetMissiles; - audioSource.PlayOneShot (clickSound); - } - - [KSPAction("Jettison Weapon")] - public void AGJettisonWeapon(KSPActionParam param) - { - if(currentMissile) - { - foreach(var missile in vessel.FindPartModulesImplementing()) - { - if(missile.GetShortName() == currentMissile.GetShortName()) - { - missile.Jettison(); - } - } - } - else if(selectedWeapon!=null && selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - foreach(var rocket in vessel.FindPartModulesImplementing()) - { - rocket.Jettison(); - } - } - } - - - [KSPField(guiActive = true, guiActiveEditor = true, guiName = "Team")] - public string teamString = "A"; - void UpdateTeamString() - { - teamString = Enum.GetName(typeof(BDArmorySettings.BDATeams), BDATargetManager.BoolToTeam(team)); - } - - - [KSPField(isPersistant = true)] - public bool team = false; - - - - [KSPAction("Toggle Team")] - public void AGToggleTeam(KSPActionParam param) - { - ToggleTeam(); - } - - public delegate void ToggleTeamDelegate(MissileFire wm, BDArmorySettings.BDATeams team); - public static event ToggleTeamDelegate OnToggleTeam; - [KSPEvent(active = true, guiActiveEditor = true, guiActive = false)] - public void ToggleTeam() - { - team = !team; - - if(HighLogic.LoadedSceneIsFlight) - { - audioSource.PlayOneShot(clickSound); - foreach(var wpnMgr in vessel.FindPartModulesImplementing()) - { - wpnMgr.team = team; - } - if(vessel.GetComponent()) - { - vessel.GetComponent().RemoveFromDatabases(); - Destroy(vessel.GetComponent()); - } - - if(OnToggleTeam != null) - { - OnToggleTeam(this, BDATargetManager.BoolToTeam(team)); - } - } - - UpdateTeamString(); - } - - [KSPField(isPersistant = true)] - public bool isArmed = false; - - - - [KSPAction("Arm/Disarm")] - public void AGToggleArm(KSPActionParam param) - { - ToggleArm(); - } - - public void ToggleArm() - { - isArmed = !isArmed; - if(isArmed) audioSource.PlayOneShot(armOnSound); - else audioSource.PlayOneShot(armOffSound); - - } - - - [KSPField(isPersistant = false, guiActive = true, guiName = "Weapon")] - public string selectedWeaponString = "None"; - - IBDWeapon sw = null; - public IBDWeapon selectedWeapon - { - get - { - if((sw == null || sw.GetPart().vessel!=vessel) && weaponIndex>0) - { - foreach(IBDWeapon weapon in vessel.FindPartModulesImplementing()) - { - if(weapon.GetShortName() == selectedWeaponString) - { - sw = weapon; - break; - } - } - } - return sw; - } - set - { - sw = value; - selectedWeaponString = GetWeaponName(value); - } - } - - [KSPAction("Fire Missile")] - public void AGFire(KSPActionParam param) - { - FireMissile(); - } - - [KSPAction("Fire Guns (Hold)")] - public void AGFireGunsHold(KSPActionParam param) - { - if(weaponIndex > 0 && (selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser)) - { - foreach(var weap in vessel.FindPartModulesImplementing()) - { - if(weap.weaponState!= ModuleWeapon.WeaponStates.Enabled || weap.GetShortName() != selectedWeapon.GetShortName()) - { - continue; - } - - weap.AGFireHold(param); - } - } - } - - [KSPAction("Fire Guns (Toggle)")] - public void AGFireGunsToggle(KSPActionParam param) - { - if(weaponIndex > 0 && (selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser)) - { - foreach(var weap in vessel.FindPartModulesImplementing()) - { - if(weap.weaponState!= ModuleWeapon.WeaponStates.Enabled || weap.GetShortName() != selectedWeapon.GetShortName()) - { - continue; - } - - weap.AGFireToggle(param); - } - } - } - - /* - [KSPEvent(guiActive = true, guiName = "Fire", active = true)] - public void GuiFire() - { - FireMissile(); - } - */ - /* - [KSPEvent(guiActive = true, guiName = "Next Weapon", active = true)] - public void GuiCycle() - { - CycleWeapon(true); - } - */ - - [KSPAction("Next Weapon")] - public void AGCycle(KSPActionParam param) - { - CycleWeapon(true); - } - - /* - [KSPEvent(guiActive = true, guiName = "Previous Weapon", active = true)] - public void GuiCycleBack() - { - CycleWeapon(false); - } - */ - - [KSPAction("Previous Weapon")] - public void AGCycleBack(KSPActionParam param) - { - CycleWeapon(false); - } - - [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "Open GUI", active = true)] - public void ToggleToolbarGUI() - { - BDArmorySettings.toolbarGuiEnabled = !BDArmorySettings.toolbarGuiEnabled; - } - - #endregion - - - public bool canRipple = false; - - public override void OnSave(ConfigNode node) - { - base.OnSave(node); - - if(HighLogic.LoadedSceneIsFlight) - { - SaveRippleOptions(node); - } - } - - public override void OnLoad(ConfigNode node) - { - base.OnLoad(node); - if(HighLogic.LoadedSceneIsFlight) - { - rippleData = string.Empty; - if(node.HasValue("RippleData")) - { - rippleData = node.GetValue("RippleData"); - } - ParseRippleOptions(); - } - } - - public override void OnStart (PartModule.StartState state) - { - UpdateMaxGuardRange(); - - startTime = Time.time; - - UpdateTeamString(); - - if(HighLogic.LoadedSceneIsFlight) - { - part.force_activate(); - - selectionMessage = new ScreenMessage("", 2, ScreenMessageStyle.LOWER_CENTER); - - UpdateList(); - if(weaponArray.Length > 0) selectedWeapon = weaponArray[weaponIndex]; - //selectedWeaponString = GetWeaponName(selectedWeapon); - - cameraTransform = part.FindModelTransform("BDARPMCameraTransform"); - - part.force_activate(); - rippleTimer = Time.time; - targetListTimer = Time.time; - - wingCommander = part.FindModuleImplementing(); - - - audioSource = gameObject.AddComponent(); - audioSource.minDistance = 1; - audioSource.maxDistance = 500; - audioSource.dopplerLevel = 0; - audioSource.spatialBlend = 1; - - warningAudioSource = gameObject.AddComponent(); - warningAudioSource.minDistance = 1; - warningAudioSource.maxDistance = 500; - warningAudioSource.dopplerLevel = 0; - warningAudioSource.spatialBlend = 1; - - targetingAudioSource = gameObject.AddComponent(); - targetingAudioSource.minDistance = 1; - targetingAudioSource.maxDistance = 250; - targetingAudioSource.dopplerLevel = 0; - targetingAudioSource.loop = true; - targetingAudioSource.spatialBlend = 1; - - StartCoroutine (MissileWarningResetRoutine()); - - if(vessel.isActiveVessel) - { - BDArmorySettings.Instance.ActiveWeaponManager = this; - } - - UpdateVolume(); - BDArmorySettings.OnVolumeChange += UpdateVolume; - BDArmorySettings.OnSavedSettings += ClampVisualRange; - - StartCoroutine(StartupListUpdater()); - - GameEvents.onVesselCreate.Add(OnVesselCreate); - GameEvents.onPartJointBreak.Add(OnPartJointBreak); - GameEvents.onPartDie.Add(OnPartDie); - - foreach(var aipilot in vessel.FindPartModulesImplementing()) - { - pilotAI = aipilot; - break; - } - } - } - - void OnPartDie(Part p) - { - if(p == part) - { - GameEvents.onPartDie.Remove(OnPartDie); - GameEvents.onPartJointBreak.Remove(OnPartJointBreak); - } - - - RefreshModules(); - UpdateList(); - } - - void OnVesselCreate(Vessel v) - { - RefreshModules(); - } - - void OnPartJointBreak(PartJoint j) - { - if(!part) - { - GameEvents.onPartJointBreak.Remove(OnPartJointBreak); - } - - if((j.Parent && j.Parent.vessel == vessel) || (j.Child && j.Child.vessel == vessel)) - { - RefreshModules(); - UpdateList(); - } - } - - IEnumerator StartupListUpdater() - { - while(vessel.packed || !FlightGlobals.ready) - { - yield return null; - if(vessel.isActiveVessel) - { - BDArmorySettings.Instance.ActiveWeaponManager = this; - } - } - UpdateList(); - } - - void UpdateVolume() - { - if(audioSource) - { - audioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; - } - if(warningAudioSource) - { - warningAudioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; - } - if(targetingAudioSource) - { - targetingAudioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; - } - } - - void OnDestroy() - { - BDArmorySettings.OnVolumeChange -= UpdateVolume; - BDArmorySettings.OnSavedSettings -= ClampVisualRange; - GameEvents.onVesselCreate.Remove(OnVesselCreate); - GameEvents.onPartJointBreak.Remove(OnPartJointBreak); - GameEvents.onPartDie.Remove(OnPartDie); - } - - - void DisplaySelectedWeaponMessage() - { - if(BDArmorySettings.GAME_UI_ENABLED && vessel == FlightGlobals.ActiveVessel) - { - ScreenMessages.RemoveMessage(selectionMessage); - selectionText = "Selected Weapon: " + GetWeaponName(weaponArray[weaponIndex]); - selectionMessage.message = selectionText; - ScreenMessages.PostScreenMessage(selectionMessage); - } - } - - - - public override void OnUpdate() - { - base.OnUpdate(); - - if(!HighLogic.LoadedSceneIsFlight) - { - return; - } - - if(!vessel.packed) - { - if(weaponIndex >= weaponArray.Length) - { - hasSingleFired = true; - triggerTimer = 0; - - weaponIndex = Mathf.Clamp(weaponIndex, 0, weaponArray.Length - 1); - - DisplaySelectedWeaponMessage(); - } - if(weaponArray.Length > 0) selectedWeapon = weaponArray[weaponIndex]; - - //finding next rocket to shoot (for aimer) - //FindNextRocket(); - - - //targeting - if(weaponIndex > 0 && (selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb)) - { - SearchForLaserPoint(); - SearchForHeatTarget(); - SearchForRadarSource(); - } - } - - UpdateTargetingAudio(); - - - if(vessel.isActiveVessel) - { - if(!CheckMouseIsOnGui() && isArmed && BDInputUtils.GetKey(BDInputSettingsFields.WEAP_FIRE_KEY)) - { - triggerTimer += Time.fixedDeltaTime; - } - else - { - triggerTimer = 0; - hasSingleFired = false; - } - - - //firing missiles and rockets=== - if( !guardMode && - selectedWeapon != null && - (selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket - || selectedWeapon.GetWeaponClass() == WeaponClasses.Missile - || selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb - )) - { - canRipple = true; - if(!MapView.MapIsEnabled && triggerTimer > BDArmorySettings.TRIGGER_HOLD_TIME && !hasSingleFired) - { - if(rippleFire) - { - if(Time.time - rippleTimer > 60f / rippleRPM) - { - FireMissile(); - rippleTimer = Time.time; - } - } - else - { - FireMissile(); - hasSingleFired = true; - } - } - } - else if(!guardMode && - selectedWeapon != null && - (selectedWeapon.GetWeaponClass() == WeaponClasses.Gun && currentGun.roundsPerMinute < 1500)) - { - canRipple = true; - } - else - { - canRipple = false; - } - } - } - - public override void OnFixedUpdate () - { - if(guardMode && vessel.IsControllable) - { - GuardMode(); - } - else - { - targetScanTimer = -100; - } - - - - if(vessel.isActiveVessel) - { - TargetAcquire(); - } - BombAimer(); - } - - void UpdateTargetingAudio() - { - if(BDArmorySettings.GameIsPaused) - { - if(targetingAudioSource.isPlaying) - { - targetingAudioSource.Stop(); - } - return; - } - - if(selectedWeapon!=null && selectedWeapon.GetWeaponClass() == WeaponClasses.Missile && vessel.isActiveVessel) - { - MissileLauncher ml = currentMissile; - if(ml.targetingMode == MissileLauncher.TargetingModes.Heat) - { - if(targetingAudioSource.clip != heatGrowlSound) - { - targetingAudioSource.clip = heatGrowlSound; - } - - if(heatTarget.exists) - { - targetingAudioSource.pitch = Mathf.MoveTowards(targetingAudioSource.pitch, 2, 8 * Time.deltaTime); - } - else - { - targetingAudioSource.pitch = Mathf.MoveTowards(targetingAudioSource.pitch, 1, 8 * Time.deltaTime); - } - - if(!targetingAudioSource.isPlaying) - { - targetingAudioSource.Play(); - } - } - else - { - if(targetingAudioSource.isPlaying) - { - targetingAudioSource.Stop(); - } - } - } - else - { - targetingAudioSource.pitch = 1; - if(targetingAudioSource.isPlaying) - { - targetingAudioSource.Stop(); - } - } - - } - - - - IEnumerator MissileWarningResetRoutine() - { - while(enabled) - { - missileIsIncoming = false; - yield return new WaitForSeconds(1); - } - } - - public void UpdateList() - { - weaponTypes.Clear(); - - foreach(IBDWeapon weapon in vessel.FindPartModulesImplementing()) - { - string weaponName = weapon.GetShortName(); - bool alreadyAdded = false; - foreach(var weap in weaponTypes) - { - if(weap.GetShortName() == weaponName) - { - alreadyAdded = true; - break; - } - } - - //dont add empty rocket pods - if(weapon.GetWeaponClass() == WeaponClasses.Rocket && weapon.GetPart().FindModuleImplementing().GetRocketResource().amount < 1) - { - continue; - } - - if(!alreadyAdded) - { - weaponTypes.Add(weapon); - } - } - - //weaponTypes.Sort(); - weaponTypes = weaponTypes.OrderBy(w => w.GetShortName()).ToList(); - - List tempList = new List(); - tempList.Add (null); - tempList.AddRange(weaponTypes); - - weaponArray = tempList.ToArray(); - - if(weaponIndex >= weaponArray.Length) - { - hasSingleFired = true; - triggerTimer = 0; - - } - - weaponIndex = Mathf.Clamp(weaponIndex, 0, weaponArray.Length - 1); - - if(selectedWeapon == null || selectedWeapon.GetPart() == null || selectedWeapon.GetPart().vessel!=vessel || GetWeaponName(selectedWeapon) != GetWeaponName(weaponArray[weaponIndex])) - { - selectedWeapon = weaponArray[weaponIndex]; - - if(vessel.isActiveVessel && Time.time - startTime > 1) - { - hasSingleFired = true; - } - - if(vessel.isActiveVessel && weaponIndex!=0) - { - DisplaySelectedWeaponMessage(); - } - } - - if(weaponIndex == 0) - { - selectedWeapon = null; - hasSingleFired = true; - } - - MissileLauncher aMl = GetAsymMissile(); - if(aMl) - { - //Debug.Log("setting asym missile: " + aMl.part.name); - selectedWeapon = aMl; - currentMissile = aMl; - } - - MissileLauncher rMl = GetRotaryReadyMissile(); - if(rMl) - { - //Debug.Log("setting rotary ready missile: " + rMl.part.name); - selectedWeapon = rMl; - currentMissile = rMl; - } - - if(selectedWeapon != null && (selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb || selectedWeapon.GetWeaponClass() == WeaponClasses.Missile)) - { - //Debug.Log("=====selected weapon: " + selectedWeapon.GetPart().name); - if(!currentMissile || currentMissile.part.name != selectedWeapon.GetPart().name) - { - currentMissile = selectedWeapon.GetPart().FindModuleImplementing(); - } - } - else - { - currentMissile = null; - } - - //selectedWeapon = weaponArray[weaponIndex]; - - //bomb stuff - if(selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) - { - bombPart = selectedWeapon.GetPart(); - } - else - { - bombPart = null; - } - - //gun ripple stuff - if(selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun && currentGun.roundsPerMinute < 1500) - { - float counter = 0; - float weaponRPM = 0; - gunRippleIndex = 0; - rippleGunCount = 0; - List tempListModuleWeapon = vessel.FindPartModulesImplementing(); - foreach (ModuleWeapon weapon in tempListModuleWeapon) - { - if (selectedWeapon.GetShortName() == weapon.GetShortName()) - { - weapon.rippleIndex = Mathf.RoundToInt(counter); - weaponRPM = weapon.roundsPerMinute; - ++counter; - rippleGunCount++; - } - } - gunRippleRpm = weaponRPM * counter; - float timeDelayPerGun = 60f / (weaponRPM * counter); //number of seconds between each gun firing; will reduce with increasing RPM or number of guns - foreach (ModuleWeapon weapon in tempListModuleWeapon) - { - if (selectedWeapon.GetShortName() == weapon.GetShortName()) - { - weapon.initialFireDelay = timeDelayPerGun; //set the time delay for moving to next index - } - } - - RippleOption ro; //ripplesetup and stuff - if (rippleDictionary.ContainsKey(selectedWeapon.GetShortName())) - { - ro = rippleDictionary[selectedWeapon.GetShortName()]; - } - else - { - ro = new RippleOption(currentGun.useRippleFire, 650); //take from gun's persistant value - rippleDictionary.Add(selectedWeapon.GetShortName(), ro); - } - - foreach (ModuleWeapon w in vessel.FindPartModulesImplementing()) - { - if (w.GetShortName() == selectedWeapon.GetShortName()) - w.useRippleFire = ro.rippleFire; - } - } - - //rocket - FindNextRocket(null); - - ToggleTurret(); - SetMissileTurrets(); - SetRocketTurrets(); - SetRotaryRails(); - } - - private bool SetCargoBays() - { - if(!guardMode) return false; - bool openingBays = false; - - if(weaponIndex > 0 && currentMissile && guardTarget && Vector3.Dot(guardTarget.transform.position-currentMissile.transform.position, currentMissile.transform.forward) > 0) - { - if(currentMissile.part.ShieldedFromAirstream) - { - foreach(var ml in vessel.FindPartModulesImplementing()) - { - if(ml.part.ShieldedFromAirstream) - { - ml.inCargoBay = true; - } - } - } - - if(currentMissile.inCargoBay) - { - foreach(var bay in vessel.FindPartModulesImplementing()) - { - if(currentMissile.part.airstreamShields.Contains(bay)) - { - ModuleAnimateGeneric anim = (ModuleAnimateGeneric)bay.part.Modules.GetModule(bay.DeployModuleIndex); - - string toggleOption = anim.Events["Toggle"].guiName; - if(toggleOption == "Open") - { - if(anim) - { - anim.Toggle(); - openingBays = true; - } - } - } - else - { - ModuleAnimateGeneric anim = (ModuleAnimateGeneric)bay.part.Modules.GetModule(bay.DeployModuleIndex); - - string toggleOption = anim.Events["Toggle"].guiName; - if(toggleOption == "Close") - { - if(anim) - { - anim.Toggle(); - } - } - } - } - } - else - { - foreach(var bay in vessel.FindPartModulesImplementing()) - { - ModuleAnimateGeneric anim = (ModuleAnimateGeneric) bay.part.Modules.GetModule(bay.DeployModuleIndex); - string toggleOption = anim.Events["Toggle"].guiName; - if(toggleOption == "Close") - { - if(anim) - { - anim.Toggle(); - } - } - } - } - } - else - { - foreach(var bay in vessel.FindPartModulesImplementing()) - { - ModuleAnimateGeneric anim = (ModuleAnimateGeneric) bay.part.Modules.GetModule(bay.DeployModuleIndex); - string toggleOption = anim.Events["Toggle"].guiName; - if(toggleOption == "Close") - { - if(anim) - { - anim.Toggle(); - } - } - } - } - - return openingBays; - } - - void SetRotaryRails() - { - if(weaponIndex == 0) return; - - if(selectedWeapon == null) return; - - if(!(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb)) return; - - if(!currentMissile) return; - - MissileLauncher cm = currentMissile; - foreach(var rotRail in vessel.FindPartModulesImplementing()) - { - if(rotRail.missileCount == 0) - { - //Debug.Log("SetRotaryRails(): rail has no missiles"); - continue; - } - - //Debug.Log("SetRotaryRails(): rotRail.readyToFire: " + rotRail.readyToFire + ", rotRail.readyMissile: " + ((rotRail.readyMissile != null) ? rotRail.readyMissile.part.name : "null") + ", rotRail.nextMissile: " + ((rotRail.nextMissile != null) ? rotRail.nextMissile.part.name : "null")); - - //Debug.Log("current missile: " + cm.part.name); - - if(rotRail.readyToFire) - { - if(!rotRail.readyMissile) - { - rotRail.RotateToMissile(cm); - return; - } - - if(rotRail.readyMissile.part.name != cm.part.name) - { - rotRail.RotateToMissile(cm); - } - } - else - { - if(!rotRail.nextMissile) - { - rotRail.RotateToMissile(cm); - } - else if(rotRail.nextMissile.part.name!=cm.part.name) - { - rotRail.RotateToMissile(cm); - } - } - - /* - if((rotRail.readyToFire && (!rotRail.readyMissile || rotRail.readyMissile.part.name!=cm.part.name)) || (!rotRail.nextMissile || rotRail.nextMissile.part.name!=cm.part.name)) - { - rotRail.RotateToMissile(cm); - } - */ - } - } - - void SetMissileTurrets() - { - foreach(var mt in vessel.FindPartModulesImplementing()) - { - if(weaponIndex > 0 && mt.ContainsMissileOfType(currentMissile)) - { - if(!mt.activeMissileOnly || currentMissile.missileTurret == mt) - { - mt.EnableTurret(); - } - else - { - mt.DisableTurret(); - } - } - else - { - mt.DisableTurret(); - } - } - } - - void SetRocketTurrets() - { - RocketLauncher currentTurret = null; - if(selectedWeapon != null && selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - RocketLauncher rl = selectedWeapon.GetPart().FindModuleImplementing(); - if(rl && rl.turret) - { - currentTurret = rl; - } - } - - foreach(var rl in vessel.FindPartModulesImplementing()) - { - rl.weaponManager = this; - if(rl.turret) - { - if(currentTurret && rl.part.name == currentTurret.part.name) - { - rl.EnableTurret(); - } - else - { - rl.DisableTurret(); - } - } - } - } - - public void CycleWeapon(bool forward) - { - - if(forward) weaponIndex++; - else weaponIndex--; - weaponIndex = (int)Mathf.Repeat(weaponIndex, weaponArray.Length); - - hasSingleFired = true; - triggerTimer = 0; - - UpdateList(); - - DisplaySelectedWeaponMessage(); - - if(vessel.isActiveVessel && !guardMode) - { - audioSource.PlayOneShot(clickSound); - } - } - - public void CycleWeapon(int index) - { - if(index >= weaponArray.Length) - { - index = 0; - } - weaponIndex = index; - - UpdateList(); - - if(vessel.isActiveVessel && !guardMode) - { - audioSource.PlayOneShot(clickSound); - - DisplaySelectedWeaponMessage(); - } - - } - - void FireCurrentMissile(bool checkClearance) - { - MissileLauncher ml = currentMissile; - if(ml == null) return; - - if(checkClearance && (!CheckBombClearance(ml) || (ml.rotaryRail&&!ml.rotaryRail.readyMissile==ml))) - { - foreach(var otherMissile in vessel.FindPartModulesImplementing()) - { - if(otherMissile != ml && otherMissile.GetShortName() == ml.GetShortName() && CheckBombClearance(otherMissile)) - { - currentMissile = otherMissile; - selectedWeapon = otherMissile; - FireCurrentMissile(false); - return; - } - } - currentMissile = ml; - selectedWeapon = ml; - return; - } - - //Part partSym = FindSym(ml.part); - if(ml.missileTurret) - { - ml.missileTurret.FireMissile(ml); - } - else if(ml.rotaryRail) - { - ml.rotaryRail.FireMissile(ml); - } - else - { - SendTargetDataToMissile(ml); - ml.FireMissile(); - } - - if(guardMode) - { - if(ml.GetWeaponClass() == WeaponClasses.Bomb) - { - StartCoroutine(BombsAwayRoutine(ml)); - } - } - else - { - if(vesselRadarData && vesselRadarData.autoCycleLockOnFire) - { - vesselRadarData.CycleActiveLock(); - } - } - - UpdateList(); - } - - - /* - public void FireMissile() - { - bool hasFired = false; - - if(selectedWeapon == null) - { - return; - } - - if(lastFiredSym && lastFiredSym.partInfo.title != selectedWeapon.GetPart().partInfo.title) - { - lastFiredSym = null; - } - - IBDWeapon firedWeapon = null; - - if(lastFiredSym != null && lastFiredSym.partName == selectedWeapon.GetPart().partName) - { - Part nextPart; - if(FindSym(lastFiredSym)!=null) - { - nextPart = FindSym(lastFiredSym); - } - else - { - nextPart = null; - } - - - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) - { - foreach(MissileLauncher ml in lastFiredSym.FindModulesImplementing()) - { - if(!CheckBombClearance(ml)) - { - lastFiredSym = null; - break; - } - - if(guardMode && guardTarget!=null && BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - firedWeapon = ml; - if(ml.missileTurret) - { - ml.missileTurret.PrepMissileForFire(ml); - ml.FireMissileOnTarget(guardTarget); - ml.missileTurret.UpdateMissileChildren(); - } - else if(ml.rotaryRail) - { - ml.rotaryRail.PrepMissileForFire(ml); - ml.FireMissileOnTarget(guardTarget); - ml.rotaryRail.UpdateMissileChildren(); - } - else - { - ml.FireMissileOnTarget(guardTarget); - } - } - else - { - firedWeapon = ml; - SendTargetDataToMissile(ml); - if(ml.missileTurret) - { - ml.missileTurret.FireMissile(ml); - } - else if(ml.rotaryRail) - { - ml.rotaryRail.FireMissile(ml); - } - else - { - ml.FireMissile(); - } - } - - hasFired = true; - - lastFiredSym = nextPart; - if(lastFiredSym != null) - { - currentMissile = lastFiredSym.GetComponent(); - selectedWeapon = currentMissile; - SetMissileTurrets(); - } - break; - } - } - else if(selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - foreach(RocketLauncher rl in lastFiredSym.FindModulesImplementing()) - { - hasFired = true; - firedWeapon = rl; - rl.FireRocket(); - //rippleRPM = rl.rippleRPM; - if(nextPart!=null) - { - foreach(PartResource r in nextPart.Resources.list) - { - if(r.amount>0) lastFiredSym = nextPart; - else lastFiredSym = null; - } - } - break; - } - } - - } - - - - if(!hasFired && lastFiredSym == null) - { - bool firedMissile = false; - foreach(MissileLauncher ml in vessel.FindPartModulesImplementing()) - { - if(ml.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) - { - if(!CheckBombClearance(ml)) - { - continue; - } - - lastFiredSym = FindSym(ml.part); - - if(guardMode && guardTarget!=null && BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - firedWeapon = ml; - if(ml.missileTurret) - { - ml.missileTurret.PrepMissileForFire(ml); - ml.FireMissileOnTarget(guardTarget); - ml.missileTurret.UpdateMissileChildren(); - } - else if(ml.rotaryRail) - { - ml.rotaryRail.PrepMissileForFire(ml); - ml.FireMissileOnTarget(guardTarget); - ml.rotaryRail.UpdateMissileChildren(); - } - else - { - ml.FireMissileOnTarget(guardTarget); - } - } - else - { - firedWeapon = ml; - SendTargetDataToMissile(ml); - if(ml.missileTurret) - { - ml.missileTurret.FireMissile(ml); - } - else if(ml.rotaryRail) - { - ml.rotaryRail.FireMissile(ml); - } - else - { - ml.FireMissile(); - } - } - firedMissile = true; - if(lastFiredSym != null) - { - currentMissile = lastFiredSym.GetComponent(); - selectedWeapon = currentMissile; - SetMissileTurrets(); - } - - break; - } - } - - if(!firedMissile) - { - foreach(RocketLauncher rl in vessel.FindPartModulesImplementing()) - { - bool hasRocket = false; - foreach(PartResource r in rl.part.Resources.list) - { - if(r.amount>0) hasRocket = true; - } - - if(rl.part.partInfo.title == selectedWeapon.GetPart().partInfo.title && hasRocket) - { - lastFiredSym = FindSym(rl.part); - firedWeapon = rl; - rl.FireRocket(); - //rippleRPM = rl.rippleRPM; - - break; - } - } - } - } - - - UpdateList(); - if(GetWeaponName(selectedWeapon) != GetWeaponName(firedWeapon)) - { - hasSingleFired = true; - } - if(weaponIndex >= weaponArray.Length) - { - triggerTimer = 0; - hasSingleFired = true; - weaponIndex = Mathf.Clamp(weaponIndex, 0, weaponArray.Length - 1); - - DisplaySelectedWeaponMessage(); - - } - - if(vesselRadarData && vesselRadarData.autoCycleLockOnFire) - { - vesselRadarData.CycleActiveLock(); - } - - }*/ - - void FireMissile() - { - if(weaponIndex == 0) - { - return; - } - - if(selectedWeapon == null) - { - return; - } - - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile || selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) - { - FireCurrentMissile(true); - } - else if(selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - if(!currentRocket || currentRocket.part.name!=selectedWeapon.GetPart().name) - { - FindNextRocket(null); - } - - if(currentRocket) - { - currentRocket.FireRocket(); - FindNextRocket(currentRocket); - } - } - - UpdateList(); - //TODO: fire rockets and take care of extra things - } - - //finds a symmetry partner - public Part FindSym(Part p) - { - foreach(Part pSym in p.symmetryCounterparts) - { - if(pSym != p && pSym.vessel == vessel) - { - return pSym; - } - } - - return null; - } - - public void SendTargetDataToMissile(MissileLauncher ml) - { - if(ml.targetingMode == MissileLauncher.TargetingModes.Laser && laserPointDetected) - { - ml.lockedCamera = foundCam; - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.GPS) - { - if(BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - if(vessel.targetObject != null && vessel.targetObject.GetVessel() != null) - { - ml.targetAcquired = true; - ml.legacyTargetVessel = vessel.targetObject.GetVessel(); - } - } - else if(designatedGPSCoords != Vector3d.zero) - { - ml.targetGPSCoords = designatedGPSCoords; - ml.targetAcquired = true; - } - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.Heat && heatTarget.exists) - { - ml.heatTarget = heatTarget; - heatTarget = TargetSignatureData.noTarget; - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.Radar && vesselRadarData && vesselRadarData.locked)//&& radar && radar.lockedTarget.exists) - { - //ml.radarTarget = radar.lockedTarget; - ml.radarTarget = vesselRadarData.lockedTargetData.targetData; - - ml.vrd = vesselRadarData; - vesselRadarData.lastMissile = ml; - /* - - if(radar.linked && radar.linkedRadar.locked) - { - ml.radar = radar.linkedRadar; - } - else - { - ml.radar = radar; - } - radar.lastMissile = ml; - */ - - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.AntiRad && antiRadTargetAcquired) - { - ml.targetAcquired = true; - ml.targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(antiRadiationTarget, vessel.mainBody); - } - } - - - public void TargetAcquire() - { - if(isArmed && BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - Vessel acquiredTarget = null; - float smallestAngle = 8; - - if(Time.time-targetListTimer > 1) - { - loadedVessels.Clear(); - - foreach(Vessel v in FlightGlobals.Vessels) - { - float viewAngle = Vector3.Angle(-transform.forward, v.transform.position-transform.position); - if(v.loaded && viewAngle < smallestAngle) - { - if(!v.vesselName.Contains("(fired)")) loadedVessels.Add(v); - } - } - } - - foreach(Vessel v in loadedVessels) - { - float viewAngle = Vector3.Angle(-transform.forward, v.transform.position-transform.position); - //if(v!= vessel && v.loaded) Debug.Log ("view angle: "+viewAngle); - if(v!= null && v != vessel && v.loaded && viewAngle < smallestAngle && CanSeeTarget(v)) - { - acquiredTarget = v; - smallestAngle = viewAngle; - } - } - - if(acquiredTarget != null && acquiredTarget != (Vessel)FlightGlobals.fetch.VesselTarget) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("found target! : " + acquiredTarget.name); - } - FlightGlobals.fetch.SetVesselTarget(acquiredTarget); - } - } - } - - - - void BombAimer() - { - if(selectedWeapon == null) - { - showBombAimer = false; - return; - } - if(!bombPart || selectedWeapon.GetPart()!=bombPart) - { - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) - { - bombPart = selectedWeapon.GetPart(); - } - else - { - showBombAimer = false; - return; - } - } - - showBombAimer = - ( - !MapView.MapIsEnabled && - vessel.isActiveVessel && - selectedWeapon !=null && - selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb && - bombPart!=null && - BDArmorySettings.DRAW_AIMERS && - vessel.verticalSpeed < 50 && - AltitudeTrigger() - ); - - if(showBombAimer || (guardMode && weaponIndex > 0 && selectedWeapon.GetWeaponClass()==WeaponClasses.Bomb)) - { - MissileLauncher ml = bombPart.GetComponent(); - - float simDeltaTime = 0.1f; - float simTime = 0; - Vector3 dragForce = Vector3.zero; - Vector3 prevPos = ml.missileReferenceTransform.position; - Vector3 currPos = ml.missileReferenceTransform.position; - Vector3 simVelocity = vessel.rb_velocity; - - simVelocity += ml.decoupleSpeed * (ml.decoupleForward ? ml.missileReferenceTransform.forward : -ml.missileReferenceTransform.up); - - List pointPositions = new List(); - pointPositions.Add(currPos); - - - prevPos = ml.missileReferenceTransform.position; - currPos = ml.missileReferenceTransform.position; - - bombAimerPosition = Vector3.zero; - - - - bool simulating = true; - while(simulating) - { - prevPos = currPos; - currPos += simVelocity * simDeltaTime; - float atmDensity = (float) FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody); - - simVelocity += FlightGlobals.getGeeForceAtPosition(currPos) * simDeltaTime; - float simSpeedSquared = simVelocity.sqrMagnitude; - float drag = ml.simpleDrag; - if(simTime > ml.deployTime) - { - drag = ml.deployedDrag; - } - dragForce = (0.008f * bombPart.mass) * drag * 0.5f * simSpeedSquared * atmDensity * simVelocity.normalized; - simVelocity -= (dragForce/bombPart.mass)*simDeltaTime; - - Ray ray = new Ray(prevPos, currPos - prevPos); - RaycastHit hitInfo; - if(Physics.Raycast(ray, out hitInfo, Vector3.Distance(prevPos, currPos), 1<<15)) - { - bombAimerPosition = hitInfo.point; - simulating = false; - } - else if(FlightGlobals.getAltitudeAtPos(currPos) < 0) - { - bombAimerPosition = currPos - (FlightGlobals.getAltitudeAtPos(currPos)*FlightGlobals.getUpAxis()); - simulating = false; - } - - simTime += simDeltaTime; - pointPositions.Add(currPos); - } - - /* - //debug lines - if(BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) - { - Vector3[] pointsArray = pointPositions.ToArray(); - LineRenderer lr = GetComponent(); - if(!lr) - { - lr = gameObject.AddComponent(); - } - lr.enabled = true; - lr.SetWidth(.1f, .1f); - lr.SetVertexCount(pointsArray.Length); - for(int i = 0; i()) - { - gameObject.GetComponent().enabled = false; - } - } - - */ - - } - - } - - bool AltitudeTrigger() - { - float maxAlt = Mathf.Clamp(BDArmorySettings.PHYSICS_RANGE * 0.75f, 2250, 5000); - double asl = vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass()); - double radarAlt = asl - vessel.terrainAltitude; - - return radarAlt < maxAlt || asl < maxAlt; - } - - void OnGUI() - { - if(HighLogic.LoadedSceneIsFlight && vessel == FlightGlobals.ActiveVessel && BDArmorySettings.GAME_UI_ENABLED && !MapView.MapIsEnabled) - { - //debug - if(BDArmorySettings.DRAW_DEBUG_LINES) - { - if(guardMode && !BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - BDGUIUtils.DrawLineBetweenWorldPositions(part.transform.position, part.transform.position + (debugGuardViewDirection * 25), 2, Color.yellow); - } - - if(incomingMissileVessel) - { - BDGUIUtils.DrawLineBetweenWorldPositions(part.transform.position, incomingMissileVessel.transform.position, 5, Color.cyan); - } - } - - - - - if(showBombAimer) - { - MissileLauncher ml = currentMissile; - if(ml) - { - float size = 128; - Texture2D texture = BDArmorySettings.Instance.greenCircleTexture; - - if(ml.guidanceActive) - { - texture = BDArmorySettings.Instance.largeGreenCircleTexture; - size = 256; - } - BDGUIUtils.DrawTextureOnWorldPos(bombAimerPosition, texture, new Vector2(size, size), 0); - } - } - - - - //MISSILE LOCK HUD - MissileLauncher missile = currentMissile; - if(missile) - { - if(missile.targetingMode == MissileLauncher.TargetingModes.Laser) - { - if(laserPointDetected && foundCam) - { - BDGUIUtils.DrawTextureOnWorldPos(foundCam.groundTargetPosition, BDArmorySettings.Instance.greenCircleTexture, new Vector2(48, 48), 1); - } - - foreach(var cam in BDATargetManager.ActiveLasers) - { - if(cam && cam.vessel != vessel && cam.surfaceDetected && cam.groundStabilized && !cam.gimbalLimitReached) - { - BDGUIUtils.DrawTextureOnWorldPos(cam.groundTargetPosition, BDArmorySettings.Instance.greenDiamondTexture, new Vector2(18, 18), 0); - } - } - } - else if(missile.targetingMode == MissileLauncher.TargetingModes.Heat) - { - if(heatTarget.exists) - { - BDGUIUtils.DrawTextureOnWorldPos(heatTarget.position, BDArmorySettings.Instance.greenCircleTexture, new Vector2(36, 36), 3); - float distanceToTarget = Vector3.Distance(heatTarget.position, currentMissile.missileReferenceTransform.position); - BDGUIUtils.DrawTextureOnWorldPos(currentMissile.missileReferenceTransform.position + (distanceToTarget * currentMissile.missileReferenceTransform.forward), BDArmorySettings.Instance.largeGreenCircleTexture, new Vector2(128, 128), 0); - Vector3 fireSolution = MissileGuidance.GetAirToAirFireSolution(currentMissile, heatTarget.position, heatTarget.velocity); - Vector3 fsDirection = (fireSolution - currentMissile.missileReferenceTransform.position).normalized; - BDGUIUtils.DrawTextureOnWorldPos(currentMissile.missileReferenceTransform.position + (distanceToTarget * fsDirection), BDArmorySettings.Instance.greenDotTexture, new Vector2(6, 6), 0); - } - else - { - BDGUIUtils.DrawTextureOnWorldPos(currentMissile.missileReferenceTransform.position + (2000 * currentMissile.missileReferenceTransform.forward), BDArmorySettings.Instance.greenCircleTexture, new Vector2(36, 36), 3); - BDGUIUtils.DrawTextureOnWorldPos(currentMissile.missileReferenceTransform.position + (2000 * currentMissile.missileReferenceTransform.forward), BDArmorySettings.Instance.largeGreenCircleTexture, new Vector2(156, 156), 0); - } - } - else if(missile.targetingMode == MissileLauncher.TargetingModes.Radar) - { - //if(radar && radar.locked) - if(vesselRadarData && vesselRadarData.locked) - { - float distanceToTarget = Vector3.Distance(vesselRadarData.lockedTargetData.targetData.predictedPosition, currentMissile.missileReferenceTransform.position); - BDGUIUtils.DrawTextureOnWorldPos(currentMissile.missileReferenceTransform.position + (distanceToTarget * currentMissile.missileReferenceTransform.forward), BDArmorySettings.Instance.dottedLargeGreenCircle, new Vector2(128, 128), 0); - //Vector3 fireSolution = MissileGuidance.GetAirToAirFireSolution(currentMissile, radar.lockedTarget.predictedPosition, radar.lockedTarget.velocity); - Vector3 fireSolution = MissileGuidance.GetAirToAirFireSolution(currentMissile, vesselRadarData.lockedTargetData.targetData.predictedPosition, vesselRadarData.lockedTargetData.targetData.velocity); - Vector3 fsDirection = (fireSolution - currentMissile.missileReferenceTransform.position).normalized; - BDGUIUtils.DrawTextureOnWorldPos(currentMissile.missileReferenceTransform.position + (distanceToTarget * fsDirection), BDArmorySettings.Instance.greenDotTexture, new Vector2(6, 6), 0); - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - string dynRangeDebug = string.Empty; - MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(missile, vesselRadarData.lockedTargetData.targetData.velocity, vesselRadarData.lockedTargetData.targetData.predictedPosition); - dynRangeDebug += "MaxDLZ: " + dlz.maxLaunchRange; - dynRangeDebug += "\nMinDLZ: " + dlz.minLaunchRange; - GUI.Label(new Rect(800, 800, 200, 200), dynRangeDebug); - } - } - } - else if(missile.targetingMode == MissileLauncher.TargetingModes.AntiRad) - { - if(rwr && rwr.rwrEnabled) - { - for(int i = 0; i < rwr.pingsData.Length; i++) - { - if(rwr.pingsData[i].exists && (rwr.pingsData[i].signalStrength == 0 || rwr.pingsData[i].signalStrength == 5) && Vector3.Dot(rwr.pingWorldPositions[i]-missile.transform.position, missile.transform.forward) > 0) - { - BDGUIUtils.DrawTextureOnWorldPos(rwr.pingWorldPositions[i], BDArmorySettings.Instance.greenDiamondTexture, new Vector2(22, 22), 0); - } - } - } - - if(antiRadTargetAcquired) - { - BDGUIUtils.DrawTextureOnWorldPos(antiRadiationTarget, BDArmorySettings.Instance.openGreenSquare, new Vector2(22, 22), 0); - } - } - - - } - - if((missile && missile.targetingMode == MissileLauncher.TargetingModes.GPS) || BDArmorySettings.Instance.showingGPSWindow) - { - if(designatedGPSCoords != Vector3d.zero) - { - BDGUIUtils.DrawTextureOnWorldPos(VectorUtils.GetWorldSurfacePostion(designatedGPSCoords, vessel.mainBody), BDArmorySettings.Instance.greenSpikedPointCircleTexture, new Vector2(22, 22), 0); - } - } - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(500, 600, 100, 100), "Missiles away: " + missilesAway); - } - } - - - - } - - bool disabledRocketAimers = false; - void FindNextRocket(RocketLauncher lastFired) - { - if(weaponIndex > 0 && selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - disabledRocketAimers = false; - - //first check sym of last fired - if(lastFired && lastFired.part.name == selectedWeapon.GetPart().name) - { - foreach(Part pSym in lastFired.part.symmetryCounterparts) - { - RocketLauncher rl = pSym.FindModuleImplementing(); - bool hasRocket = false; - foreach(PartResource r in rl.part.Resources.list) - { - if(r.resourceName == rl.rocketType && r.amount > 0) - { - hasRocket = true; - break; - } - } - - if(hasRocket) - { - if(currentRocket) currentRocket.drawAimer = false; - - rl.drawAimer = true; - currentRocket = rl; - selectedWeapon = currentRocket; - return; - } - } - } - - if(!lastFired && currentRocket && currentRocket.part.name == selectedWeapon.GetPart().name) - { - currentRocket.drawAimer = true; - selectedWeapon = currentRocket; - return; - } - - //then check for other rocket - bool foundRocket = false; - foreach(RocketLauncher rl in vessel.FindPartModulesImplementing()) - { - if(!foundRocket && rl.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) - { - bool hasRocket = false; - foreach(PartResource r in rl.part.Resources.list) - { - if(r.amount>0) hasRocket = true; - else - { - rl.drawAimer = false; - } - } - - if(!hasRocket) continue; - - if(currentRocket != null) currentRocket.drawAimer = false; - rl.drawAimer = true; - currentRocket = rl; - selectedWeapon = currentRocket; - //return; - foundRocket = true; - } - else - { - rl.drawAimer = false; - } - } - } - //not using a rocket, disable reticles. - else if(!disabledRocketAimers) - { - foreach(RocketLauncher rl in vessel.FindPartModulesImplementing()) - { - rl.drawAimer = false; - currentRocket = null; - } - disabledRocketAimers = true; - } - - } - - public void ResetGuardInterval() - { - targetScanTimer = 0; - } - - - void GuardMode() - { - if(!gameObject.activeInHierarchy) - { - return; - } - - if(BDArmorySettings.PEACE_MODE) - { - return; - } - - if(!BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - UpdateGuardViewScan(); - } - - //setting turrets to guard mode - if(selectedWeapon!=null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) - { - foreach(var weapon in vessel.FindPartModulesImplementing()) //make this not have to go every frame - { - if(weapon.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) - { - weapon.EnableWeapon(); - weapon.aiControlled = true; - weapon.maxAutoFireCosAngle = vessel.LandedOrSplashed ? 0.9993908f : 0.9975641f; //2 : 4 degrees - } - } - - } - - if(guardTarget) - { - //release target if out of range - if(BDArmorySettings.ALLOW_LEGACY_TARGETING && (guardTarget.transform.position-transform.position).magnitude > guardRange) - { - SetTarget(null); - } - } - else if(selectedWeapon!=null && selectedWeapon.GetWeaponClass() == WeaponClasses.Gun) - { - foreach(var weapon in vessel.FindPartModulesImplementing()) - { - if(weapon.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) - { - weapon.autoFire = false; - weapon.legacyTargetVessel = null; - } - } - } - - if(missileIsIncoming) - { - if(!isLegacyCMing) - { - StartCoroutine(LegacyCMRoutine()); - } - - targetScanTimer -= Time.fixedDeltaTime; //advance scan timing (increased urgency) - } - - //scan and acquire new target - if(Time.time-targetScanTimer > targetScanInterval) - { - targetScanTimer = Time.time; - - if(!guardFiringMissile) - { - SetTarget(null); - if(BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - ScanAllTargets(); - } - - SmartFindTarget(); - - if(guardTarget == null || selectedWeapon == null) - { - SetCargoBays(); - return; - } - - //firing - if(weaponIndex > 0) - { - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) - { - bool launchAuthorized = true; - bool pilotAuthorized = true;//(!pilotAI || pilotAI.GetLaunchAuthorization(guardTarget, this)); - - float targetAngle = Vector3.Angle(-transform.forward, guardTarget.transform.position - transform.position); - float targetDistance = Vector3.Distance(currentTarget.position, transform.position); - MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(currentMissile, guardTarget.srf_velocity, guardTarget.CoM); - if(targetAngle > guardAngle / 2) //dont fire yet if target out of guard angle - { - launchAuthorized = false; - } - else if(targetDistance > dlz.maxLaunchRange || targetDistance < dlz.minLaunchRange) //fire the missile only if target is further than missiles min launch range - { - launchAuthorized = false; - } - - if(missilesAway < maxMissilesOnTarget) - { - if(!guardFiringMissile && launchAuthorized && (pilotAuthorized || !BDArmorySettings.ALLOW_LEGACY_TARGETING)) - { - StartCoroutine(GuardMissileRoutine()); - } - } - - if(!launchAuthorized || !pilotAuthorized || missilesAway >= maxMissilesOnTarget) - { - targetScanTimer -= 0.5f * targetScanInterval; - } - } - else if(selectedWeapon.GetWeaponClass() == WeaponClasses.Bomb) - { - - if(!guardFiringMissile) - { - StartCoroutine(GuardBombRoutine()); - } - } - else if(selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket || selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser) - { - StartCoroutine(GuardTurretRoutine()); - } - } - } - SetCargoBays(); - } - - if(overrideTimer > 0) - { - overrideTimer -= TimeWarp.fixedDeltaTime; - } - else - { - overrideTimer = 0; - overrideTarget = null; - } - } - - Vector3 debugGuardViewDirection; - bool focusingOnTarget = false; - float focusingOnTargetTimer = 0; - public Vector3 incomingThreatPosition; - public Vessel incomingThreatVessel; - void UpdateGuardViewScan() - { - float finalMaxAngle = guardAngle / 2; - float finalScanDirectionAngle = currentGuardViewAngle; - if(guardTarget != null) - { - if(focusingOnTarget) - { - if(focusingOnTargetTimer > 3) - { - focusingOnTargetTimer = 0; - focusingOnTarget = false; - } - else - { - focusingOnTargetTimer += Time.fixedDeltaTime; - } - finalMaxAngle = 20; - finalScanDirectionAngle = VectorUtils.SignedAngle(viewReferenceTransform.forward, guardTarget.transform.position - viewReferenceTransform.position, viewReferenceTransform.right) + currentGuardViewAngle; - } - else - { - if(focusingOnTargetTimer > 2) - { - focusingOnTargetTimer = 0; - focusingOnTarget = true; - } - else - { - focusingOnTargetTimer += Time.fixedDeltaTime; - } - } - } - - - float angleDelta = guardViewScanRate * Time.fixedDeltaTime; - ViewScanResults results; - debugGuardViewDirection = RadarUtils.GuardScanInDirection(this, finalScanDirectionAngle, viewReferenceTransform, angleDelta, out results, BDArmorySettings.MAX_GUARD_VISUAL_RANGE); - - currentGuardViewAngle += guardViewScanDirection * angleDelta; - if(Mathf.Abs(currentGuardViewAngle) > finalMaxAngle) - { - currentGuardViewAngle = Mathf.Sign(currentGuardViewAngle) * finalMaxAngle; - guardViewScanDirection = -guardViewScanDirection; - } - - if(results.foundMissile) - { - if(rwr && !rwr.rwrEnabled) - { - rwr.EnableRWR(); - } - } - - if(results.foundHeatMissile) - { - if(!isFlaring) - { - StartCoroutine(FlareRoutine(2.5f)); - StartCoroutine(ResetMissileThreatDistanceRoutine()); - } - incomingThreatPosition = results.threatPosition; - - if(results.threatVessel) - { - if(!incomingMissileVessel || (incomingMissileVessel.transform.position - vessel.transform.position).sqrMagnitude > (results.threatVessel.transform.position - vessel.transform.position).sqrMagnitude) - { - incomingMissileVessel = results.threatVessel; - } - } - } - - if(results.foundRadarMissile) - { - FireChaff(); - incomingThreatPosition = results.threatPosition; - - if(results.threatVessel) - { - if(!incomingMissileVessel || (incomingMissileVessel.transform.position - vessel.transform.position).sqrMagnitude > (results.threatVessel.transform.position - vessel.transform.position).sqrMagnitude) - { - incomingMissileVessel = results.threatVessel; - } - } - } - - if(results.foundAGM) - { - //do smoke CM here. - if(targetMissiles && guardTarget==null) - { - //targetScanTimer = Mathf.Min(targetScanInterval, Time.time - targetScanInterval + 0.5f); - targetScanTimer -= targetScanInterval/2; - } - } - - incomingMissileDistance = Mathf.Min(results.missileThreatDistance, incomingMissileDistance); - - if(results.firingAtMe) - { - incomingThreatPosition = results.threatPosition; - if(ufRoutine != null) - { - StopCoroutine(ufRoutine); - underFire = false; - } - if (results.threatWeaponManager != null) - { - TargetInfo nearbyFriendly = BDATargetManager.GetClosestFriendly(this); - TargetInfo nearbyThreat = BDATargetManager.GetTargetFromWeaponManager(results.threatWeaponManager); - - if (nearbyThreat != null && nearbyFriendly != null) - if (nearbyThreat.weaponManager.team != this.team && nearbyFriendly.weaponManager.team == this.team) //turns out that there's no check for AI on the same team going after each other due to this. Who knew? - { - if (nearbyThreat == this.currentTarget && nearbyFriendly.weaponManager.currentTarget != null) //if being attacked by the current target, switch to the target that the nearby friendly was engaging instead - { - this.SetOverrideTarget(nearbyFriendly.weaponManager.currentTarget); - nearbyFriendly.weaponManager.SetOverrideTarget(nearbyThreat); - if (BDArmorySettings.DRAW_DEBUG_LABELS) - Debug.Log(vessel.vesselName + " called for help from " + nearbyFriendly.Vessel.vesselName + " and took its target in return"); - //basically, swap targets to cover each other - } - else - { - //otherwise, continue engaging the current target for now - nearbyFriendly.weaponManager.SetOverrideTarget(nearbyThreat); - if (BDArmorySettings.DRAW_DEBUG_LABELS) - Debug.Log(vessel.vesselName + " called for help from " + nearbyFriendly.Vessel.vesselName); - } - } - } - ufRoutine = StartCoroutine(UnderFireRoutine()); - } - } - - public void ForceWideViewScan() - { - focusingOnTarget = false; - focusingOnTargetTimer = 1; - } - - public void ForceScan() - { - targetScanTimer = -100; - } - - - IEnumerator ResetMissileThreatDistanceRoutine() - { - yield return new WaitForSeconds(8); - incomingMissileDistance = float.MaxValue; - } - - - public bool underFire = false; - Coroutine ufRoutine = null; - IEnumerator UnderFireRoutine() - { - underFire = true; - yield return new WaitForSeconds(3); - underFire = false; - } - - - - IEnumerator GuardTurretRoutine() - { - if(gameObject.activeInHierarchy && !BDArmorySettings.ALLOW_LEGACY_TARGETING) //target is out of visual range, try using sensors - { - if(guardTarget.LandedOrSplashed) - { - if(targetingPods.Count > 0) - { - foreach(var tgp in targetingPods) - { - if(tgp.enabled && (!tgp.cameraEnabled || !tgp.groundStabilized || (tgp.groundTargetPosition - guardTarget.transform.position).magnitude > 20)) - { - tgp.EnableCamera(); - yield return StartCoroutine(tgp.PointToPositionRoutine(guardTarget.CoM)); - if(tgp) - { - if(tgp.groundStabilized && guardTarget && (tgp.groundTargetPosition - guardTarget.transform.position).magnitude < 20) - { - tgp.slaveTurrets = true; - StartGuardTurretFiring(); - yield break; - } - else - { - tgp.DisableCamera(); - } - } - } - - } - } - - if(!guardTarget||(guardTarget.transform.position - transform.position).magnitude > guardRange) - { - SetTarget(null);//disengage, sensors unavailable. - yield break; - } - } - else - { - if(!vesselRadarData || !(vesselRadarData.radarCount > 0)) - { - foreach(var rd in radars) - { - if(rd.canLock) - { - rd.EnableRadar(); - break; - } - } - } - - if(vesselRadarData && (!vesselRadarData.locked || (vesselRadarData.lockedTargetData.targetData.predictedPosition - guardTarget.transform.position).magnitude >40)) - { - //vesselRadarData.TryLockTarget(guardTarget.transform.position); - vesselRadarData.TryLockTarget(guardTarget); - yield return new WaitForSeconds(0.5f); - if(guardTarget && vesselRadarData && vesselRadarData.locked && vesselRadarData.lockedTargetData.vessel == guardTarget) - { - vesselRadarData.SlaveTurrets(); - StartGuardTurretFiring(); - yield break; - } - } - - if(!guardTarget || (guardTarget.transform.position - transform.position).magnitude > guardRange) - { - SetTarget(null);//disengage, sensors unavailable. - yield break; - } - } - } - - - StartGuardTurretFiring(); - yield break; - } - - - - void StartGuardTurretFiring() - { - if(!guardTarget) return; - - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - foreach(var weapon in vessel.FindPartModulesImplementing()) - { - if(weapon.GetShortName() == selectedWeaponString) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Setting rocket to auto fire"); - } - weapon.legacyGuardTarget = guardTarget; - weapon.autoFireStartTime = Time.time; - weapon.autoFireDuration = targetScanInterval / 2; - weapon.autoRippleRate = rippleFire ? rippleRPM : 0; - } - } - } - else - { - foreach(var weapon in vessel.FindPartModulesImplementing()) - { - if(weapon.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) - { - weapon.legacyTargetVessel = guardTarget; - weapon.autoFireTimer = Time.time; - weapon.autoFireLength = 3 * targetScanInterval / 4; - } - } - } - } - - - int missilesAway = 0; - IEnumerator MissileAwayRoutine(MissileLauncher ml) - { - missilesAway++; - float missileThrustTime = ml.dropTime + ml.cruiseTime + ml.boostTime; - float timeStart = Time.time; - float timeLimit = Mathf.Max(missileThrustTime + 4, 10); - while(ml) - { - if(ml.guidanceActive && Time.time-timeStart < timeLimit) - { - yield return null; - } - else - { - break; - } - } - missilesAway--; - } - - IEnumerator BombsAwayRoutine(MissileLauncher ml) - { - missilesAway++; - float timeStart = Time.time; - float timeLimit = 3; - while(ml) - { - if(Time.time - timeStart < timeLimit) - { - yield return null; - } - else - { - break; - } - } - missilesAway--; - } - - - bool guardFiringMissile = false; - IEnumerator GuardMissileRoutine() - { - MissileLauncher ml = currentMissile; - - if(ml && !guardFiringMissile) - { - guardFiringMissile = true; - - - if(BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Firing on target: " + guardTarget.GetName() + ", (legacy targeting)"); - } - if(ml.missileTurret) - { - ml.missileTurret.PrepMissileForFire(ml); - ml.FireMissileOnTarget(guardTarget); - ml.missileTurret.UpdateMissileChildren(); - } - else - { - ml.FireMissileOnTarget(guardTarget); - } - StartCoroutine(MissileAwayRoutine(ml)); - UpdateList(); - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.Radar && vesselRadarData) - { - float attemptLockTime = Time.time; - while((!vesselRadarData.locked || (vesselRadarData.lockedTargetData.vessel != guardTarget)) && Time.time-attemptLockTime < 2) - { - if(vesselRadarData.locked) - { - vesselRadarData.UnlockAllTargets(); - yield return null; - } - //vesselRadarData.TryLockTarget(guardTarget.transform.position+(guardTarget.rb_velocity*Time.fixedDeltaTime)); - vesselRadarData.TryLockTarget(guardTarget); - yield return new WaitForSeconds(0.25f); - } - - if(ml && pilotAI && guardTarget && vesselRadarData.locked) - { - SetCargoBays(); - float LAstartTime = Time.time; - while(guardTarget && Time.time-LAstartTime < 3 && pilotAI && !pilotAI.GetLaunchAuthorization(guardTarget, this)) - { - yield return new WaitForFixedUpdate(); - } - - yield return new WaitForSeconds(0.5f); - } - - //wait for missile turret to point at target - if(guardTarget && ml && ml.missileTurret && vesselRadarData.locked) - { - vesselRadarData.SlaveTurrets(); - float turretStartTime = Time.time; - while(Time.time - turretStartTime < 5) - { - float angle = Vector3.Angle(ml.missileTurret.finalTransform.forward, ml.missileTurret.slavedTargetPosition - ml.missileTurret.finalTransform.position); - if(angle < 1) - { - turretStartTime -= 2 * Time.fixedDeltaTime; - } - yield return new WaitForFixedUpdate(); - } - } - - yield return null; - - if(ml && guardTarget && vesselRadarData.locked && (!pilotAI || pilotAI.GetLaunchAuthorization(guardTarget, this))) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Firing on target: " + guardTarget.GetName()); - } - FireCurrentMissile(true); - StartCoroutine(MissileAwayRoutine(ml)); - } - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.Heat) - { - if(vesselRadarData && vesselRadarData.locked) - { - vesselRadarData.UnlockAllTargets(); - vesselRadarData.UnslaveTurrets(); - } - float attemptStartTime = Time.time; - float attemptDuration = Mathf.Max(targetScanInterval * 0.75f, 5f); - SetCargoBays(); - while(ml && Time.time - attemptStartTime < attemptDuration && (!heatTarget.exists || (heatTarget.predictedPosition - guardTarget.transform.position).magnitude >40)) - { - //try using missile turret to lock target - if(ml.missileTurret) - { - ml.missileTurret.slaved = true; - ml.missileTurret.slavedTargetPosition = guardTarget.CoM; - ml.missileTurret.SlavedAim(); - } - - yield return new WaitForFixedUpdate(); - } - - - - //try uncaged IR lock with radar - if(guardTarget && !heatTarget.exists && vesselRadarData && vesselRadarData.radarCount > 0) - { - if(!vesselRadarData.locked || (vesselRadarData.lockedTargetData.targetData.predictedPosition - guardTarget.transform.position).magnitude > 40) - { - //vesselRadarData.TryLockTarget(guardTarget.transform.position); - vesselRadarData.TryLockTarget(guardTarget); - yield return new WaitForSeconds(Mathf.Min(1, (targetScanInterval * 0.25f))); - } - } - - if(guardTarget && ml && heatTarget.exists && pilotAI) - { - float LAstartTime = Time.time; - while(Time.time-LAstartTime < 3 && pilotAI && !pilotAI.GetLaunchAuthorization(guardTarget, this)) - { - yield return new WaitForFixedUpdate(); - } - - yield return new WaitForSeconds(0.5f); - } - - //wait for missile turret to point at target - if(ml && ml.missileTurret && heatTarget.exists) - { - float turretStartTime = attemptStartTime; - while(heatTarget.exists && Time.time - turretStartTime < Mathf.Max(targetScanInterval/2f, 2)) - { - float angle = Vector3.Angle(ml.missileTurret.finalTransform.forward, ml.missileTurret.slavedTargetPosition - ml.missileTurret.finalTransform.position); - ml.missileTurret.slaved = true; - ml.missileTurret.slavedTargetPosition = MissileGuidance.GetAirToAirFireSolution(ml, heatTarget.predictedPosition, heatTarget.velocity); - ml.missileTurret.SlavedAim(); - - if(angle < 1) - { - turretStartTime -= 3 * Time.fixedDeltaTime; - } - yield return new WaitForFixedUpdate(); - } - } - - yield return null; - - if(guardTarget && ml && heatTarget.exists && (!pilotAI || pilotAI.GetLaunchAuthorization(guardTarget, this))) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Firing on target: " + guardTarget.GetName()); - } - - FireCurrentMissile(true); - StartCoroutine(MissileAwayRoutine(ml)); - } - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.GPS) - { - designatedGPSInfo = new GPSTargetInfo(VectorUtils.WorldPositionToGeoCoords(guardTarget.CoM, vessel.mainBody), guardTarget.vesselName.Substring(0, Mathf.Min(12, guardTarget.vesselName.Length))); - FireCurrentMissile(true); - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.AntiRad) - { - if(rwr) - { - rwr.EnableRWR(); - } - - float attemptStartTime = Time.time; - float attemptDuration = targetScanInterval * 0.75f; - while(Time.time - attemptStartTime < attemptDuration && (!antiRadTargetAcquired || (antiRadiationTarget - guardTarget.CoM).magnitude > 20)) - { - yield return new WaitForFixedUpdate(); - } - - if(SetCargoBays()) - { - yield return new WaitForSeconds(1f); - } - - if(ml && antiRadTargetAcquired && (antiRadiationTarget - guardTarget.CoM).magnitude < 20) - { - FireCurrentMissile(true); - StartCoroutine(MissileAwayRoutine(ml)); - } - } - else if(ml.targetingMode == MissileLauncher.TargetingModes.Laser) - { - if(targetingPods.Count > 0) //if targeting pods are available, slew them onto target and lock. - { - foreach(var tgp in targetingPods) - { - tgp.EnableCamera(); - yield return StartCoroutine(tgp.PointToPositionRoutine(guardTarget.CoM)); - - if(tgp) - { - if(tgp.groundStabilized && (tgp.groundTargetPosition - guardTarget.transform.position).magnitude < 20) - { - break; - } - else - { - tgp.DisableCamera(); - } - } - } - } - - //search for a laser point that corresponds with target vessel - float attemptStartTime = Time.time; - float attemptDuration = targetScanInterval * 0.75f; - while(Time.time - attemptStartTime < attemptDuration && (!laserPointDetected || (foundCam && (foundCam.groundTargetPosition - guardTarget.CoM).magnitude >20))) - { - yield return new WaitForFixedUpdate(); - } - if(SetCargoBays()) - { - yield return new WaitForSeconds(1f); - } - if(ml && laserPointDetected && foundCam && (foundCam.groundTargetPosition - guardTarget.CoM).magnitude < 20) - { - FireCurrentMissile(true); - StartCoroutine(MissileAwayRoutine(ml)); - } - } - - - guardFiringMissile = false; - } - } - - IEnumerator GuardBombRoutine() - { - guardFiringMissile = true; - bool hasSetCargoBays = false; - float bombStartTime = Time.time; - float bombAttemptDuration = Mathf.Max(targetScanInterval, 12f); - float radius = currentMissile.blastRadius * Mathf.Min((1 + ((float)maxMissilesOnTarget/2f)), 1.5f); - if(currentMissile.targetingMode == MissileLauncher.TargetingModes.GPS && Vector3.Distance(designatedGPSInfo.worldPos, guardTarget.CoM) > currentMissile.blastRadius) - { - //check database for target first - float twoxsqrRad = 4f * radius * radius; - bool foundTargetInDatabase = false; - foreach(var gps in BDATargetManager.GPSTargets[BDATargetManager.BoolToTeam(team)]) - { - if((gps.worldPos - guardTarget.CoM).sqrMagnitude < twoxsqrRad) - { - designatedGPSInfo = gps; - foundTargetInDatabase = true; - break; - } - } - - - //no target in gps database, acquire via targeting pod - if(!foundTargetInDatabase) - { - ModuleTargetingCamera tgp = null; - foreach(var t in targetingPods) - { - if(t) tgp = t; - } - - if(tgp) - { - tgp.EnableCamera(); - yield return StartCoroutine(tgp.PointToPositionRoutine(guardTarget.CoM)); - - if(tgp) - { - if(guardTarget && tgp.groundStabilized && Vector3.Distance(tgp.groundTargetPosition, guardTarget.transform.position) < currentMissile.blastRadius) - { - radius = 500; - designatedGPSInfo = new GPSTargetInfo(tgp.bodyRelativeGTP, "Guard Target"); - bombStartTime = Time.time; - } - else//failed to acquire target via tgp, cancel. - { - tgp.DisableCamera(); - designatedGPSInfo = new GPSTargetInfo(); - guardFiringMissile = false; - yield break; - } - } - else//no gps target and lost tgp, cancel. - { - guardFiringMissile = false; - yield break; - } - } - else //no gps target and no tgp, cancel. - { - guardFiringMissile = false; - yield break; - } - } - } - - bool doProxyCheck = true; - - float prevDist = 2 * radius; - radius = Mathf.Max(radius, 50f); - while(guardTarget && Time.time-bombStartTime < bombAttemptDuration && weaponIndex > 0 && weaponArray[weaponIndex].GetWeaponClass()==WeaponClasses.Bomb && missilesAway < maxMissilesOnTarget) - { - float targetDist = Vector3.Distance(bombAimerPosition, guardTarget.CoM); - - if(targetDist < (radius * 20f) && !hasSetCargoBays) - { - SetCargoBays(); - hasSetCargoBays = true; - } - - if(targetDist > radius) - { - if(targetDist < Mathf.Max(radius * 2, 800f) && Vector3.Dot(guardTarget.CoM - bombAimerPosition, guardTarget.CoM - transform.position) < 0) - { - pilotAI.RequestExtend(guardTarget.CoM); - break; - } - yield return null; - } - else - { - if(doProxyCheck) - { - if(targetDist - prevDist > 0) - { - doProxyCheck = false; - } - else - { - prevDist = targetDist; - } - } - - if(!doProxyCheck) - { - FireCurrentMissile(true); - timeBombReleased = Time.time; - yield return new WaitForSeconds(rippleFire ? 60f / rippleRPM : 0.06f); - if(missilesAway >= maxMissilesOnTarget) - { - yield return new WaitForSeconds(1f); - if(pilotAI) - { - pilotAI.RequestExtend(guardTarget.CoM); - } - } - } - else - { - yield return null; - } - } - } - - designatedGPSInfo = new GPSTargetInfo(); - guardFiringMissile = false; - } - - bool SmartPickWeapon(TargetInfo target, float turretRange) - { - if(!target) - { - return false; - } - - - if(pilotAI && pilotAI.pilotEnabled && vessel.LandedOrSplashed) - { - return false; - } - - - - float distance = Vector3.Distance(transform.position+vessel.srf_velocity, target.position+target.velocity); //take velocity into account (test) - if(distance < turretRange || (target.isMissile && distance < turretRange*1.5f)) - { - if((target.isMissile) && SwitchToLaser()) //need to favor ballistic for ground units - { - return true; - } - - if(!targetMissiles && !vessel.LandedOrSplashed && target.isMissile) - { - return false; - } - - if(SwitchToTurret(distance)) - { - //dont fire on missiles if airborne unless equipped with laser - return true; - } - - } - - if(distance > turretRange || !vessel.LandedOrSplashed) - { - //missiles - if(!target.isLanded) - { - if(!targetMissiles && target.isMissile && !vessel.LandedOrSplashed) //don't fire on missiles if airborne - { - return false; - } - - if(SwitchToAirMissile ()) //Use missiles if available - { - if(currentMissile.targetingMode == MissileLauncher.TargetingModes.Radar) - { - foreach(var rd in radars) - { - if(rd.canLock) - { - rd.EnableRadar(); - break; - } - } - } - return true; - } - //return SwitchToTurret(distance); //Long range turrets? - return false; - } - else - { - if(SwitchToGroundMissile()) - { - return true; - } - else if(SwitchToBomb()) - { - return true; - } - } - } - - return false; - } - - bool TryPickAntiRad(TargetInfo target) - { - CycleWeapon(0); //go to start of array - while(true) - { - CycleWeapon(true); - if(selectedWeapon == null) return false; - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) - { - foreach(var ml in selectedWeapon.GetPart().FindModulesImplementing()) - { - if(ml.targetingMode == MissileLauncher.TargetingModes.AntiRad) - { - return true; - } - else - { - break; - } - } - //return; - } - } - } - - public bool CanSeeTarget(Vessel target) - { - if(RadarUtils.TerrainCheck(target.transform.position, transform.position)) - { - return false; - } - else - { - return true; - } - } - - void ScanAllTargets() - { - //get a target. - //float angle = 0; - - foreach(Vessel v in FlightGlobals.Vessels) - { - if(v.loaded) - { - float distance = (transform.position-v.transform.position).magnitude; - if(distance < guardRange && CanSeeTarget(v)) - { - float angle = Vector3.Angle (-transform.forward, v.transform.position-transform.position); - if(angle < guardAngle/2) - { - foreach(var missile in v.FindPartModulesImplementing()) - { - if(missile.hasFired && missile.team != team) - { - BDATargetManager.ReportVessel(v, this); - if(!isFlaring && missile.targetingMode == MissileLauncher.TargetingModes.Heat && Vector3.Angle(missile.transform.forward, transform.position - missile.transform.position) < 20) - { - StartCoroutine(FlareRoutine(targetScanInterval * 0.75f)); - } - break; - } - } - - foreach(var mF in v.FindPartModulesImplementing()) - { - if(mF.team != team && mF.vessel.IsControllable && mF.vessel.isCommandable) //added iscommandable check - { - BDATargetManager.ReportVessel(v, this); - break; - } - } - } - } - } - } - - } - - void SmartFindTarget() - { - List targetsTried = new List(); - - if (overrideTarget) //begin by checking the override target, since that takes priority - { - targetsTried.Add(overrideTarget); - SetTarget(overrideTarget); - if(SmartPickWeapon(overrideTarget, gunRange)) - { - if (BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging an override target with " + selectedWeapon); - } - overrideTimer = 15f; - //overrideTarget = null; - return; - } - else if (BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging an override target with failed to engage its override target!"); - } - } - overrideTarget = null; //null the override target if it cannot be used - - //if AIRBORNE, try to engage airborne target first - if(!vessel.LandedOrSplashed && !targetMissiles) - { - if (pilotAI && pilotAI.IsExtending) - { - TargetInfo potentialAirTarget = BDATargetManager.GetAirToAirTargetAbortExtend(this, 1500, 0.2f); - if (potentialAirTarget) - { - targetsTried.Add(potentialAirTarget); - SetTarget(potentialAirTarget); - if (SmartPickWeapon(potentialAirTarget, gunRange)) - { - if (BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is aborting extend and engaging an incoming airborne target with " + selectedWeapon); - } - return; - } - } - } - else - { - TargetInfo potentialAirTarget = BDATargetManager.GetAirToAirTarget(this); - if (potentialAirTarget) - { - targetsTried.Add(potentialAirTarget); - SetTarget(potentialAirTarget); - if (SmartPickWeapon(potentialAirTarget, gunRange)) - { - if (BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging an airborne target with " + selectedWeapon); - } - return; - } - } - } - } - - TargetInfo potentialTarget = null; - //=========HIGH PRIORITY MISSILES============= - //first engage any missiles targeting this vessel - potentialTarget = BDATargetManager.GetMissileTarget(this, true); - if(potentialTarget) - { - targetsTried.Add(potentialTarget); - SetTarget(potentialTarget); - if(SmartPickWeapon(potentialTarget, gunRange)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging incoming missile with " + selectedWeapon); - } - return; - } - } - - //then engage any missiles that are not engaged - potentialTarget = BDATargetManager.GetUnengagedMissileTarget(this); - if(potentialTarget) - { - targetsTried.Add(potentialTarget); - SetTarget(potentialTarget); - if(SmartPickWeapon(potentialTarget, gunRange)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging unengaged missile with " + selectedWeapon); - } - return; - } - } - - - //=========END HIGH PRIORITY MISSILES============= - - //============VESSEL THREATS============ - if(!targetMissiles) - { - //then try to engage enemies with least friendlies already engaging them - potentialTarget = BDATargetManager.GetLeastEngagedTarget(this); - if(potentialTarget) - { - targetsTried.Add(potentialTarget); - SetTarget(potentialTarget); - if(!BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - if(CrossCheckWithRWR(potentialTarget) && TryPickAntiRad(potentialTarget)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging the least engaged radar target with " + selectedWeapon.GetShortName()); - } - return; - } - } - if(SmartPickWeapon(potentialTarget, gunRange)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging the least engaged target with " + selectedWeapon.GetShortName()); - } - return; - } - - } - - //then engage the closest enemy - potentialTarget = BDATargetManager.GetClosestTarget(this); - if(potentialTarget) - { - targetsTried.Add(potentialTarget); - SetTarget(potentialTarget); - if(!BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - if(CrossCheckWithRWR(potentialTarget) && TryPickAntiRad(potentialTarget)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging the closest radar target with " + selectedWeapon.GetShortName()); - } - return; - } - } - if(SmartPickWeapon(potentialTarget, gunRange)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging the closest target with " + selectedWeapon.GetShortName()); - } - return; - } - /* - else - { - if(SmartPickWeapon(potentialTarget, 10000)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging the closest target with extended turret range (" + selectedWeapon.GetShortName() + ")"); - } - return; - } - } - */ - - } - } - //============END VESSEL THREATS============ - - - //============LOW PRIORITY MISSILES========= - //try to engage least engaged hostile missiles first - potentialTarget = BDATargetManager.GetMissileTarget(this); - if(potentialTarget) - { - targetsTried.Add(potentialTarget); - SetTarget(potentialTarget); - if(SmartPickWeapon(potentialTarget, gunRange)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging a missile with " + selectedWeapon.GetShortName()); - } - return; - } - } - - //then try to engage closest hostile missile - potentialTarget = BDATargetManager.GetClosestMissileTarget(this); - if(potentialTarget) - { - targetsTried.Add(potentialTarget); - SetTarget(potentialTarget); - if(SmartPickWeapon(potentialTarget, gunRange)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging a missile with " + selectedWeapon.GetShortName()); - } - return; - } - } - //==========END LOW PRIORITY MISSILES============= - - if(targetMissiles)//NO MISSILES BEYOND THIS POINT// - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is disengaging - no valid weapons"); - } - CycleWeapon(0); - SetTarget(null); - return; - } - - //if nothing works, get all remaining targets and try weapons against them - List finalTargets = BDATargetManager.GetAllTargetsExcluding(targetsTried, this); - foreach(TargetInfo finalTarget in finalTargets) - { - SetTarget(finalTarget); - if(SmartPickWeapon(finalTarget, gunRange)) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is engaging a final target with " + selectedWeapon.GetShortName()); - } - return; - } - } - - - //no valid targets found - if(potentialTarget == null || selectedWeapon == null) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " is disengaging - no valid weapons"); - } - CycleWeapon(0); - SetTarget(null); - if(vesselRadarData && vesselRadarData.locked) - { - vesselRadarData.UnlockAllTargets(); - } - return; - } - - Debug.Log ("Unhandled target case."); - } - - bool CrossCheckWithRWR(TargetInfo v) - { - bool matchFound = false; - if(rwr && rwr.rwrEnabled) - { - for(int i = 0; i < rwr.pingsData.Length; i++) - { - if(rwr.pingsData[i].exists && (rwr.pingWorldPositions[i] - v.position).magnitude < 20) - { - matchFound = true; - break; - } - } - } - - return matchFound; - } - - public void SetOverrideTarget(TargetInfo target) - { - overrideTarget = target; - targetScanTimer = -100; //force target update - } - - void SetTarget(TargetInfo target) - { - if(target) - { - if(currentTarget) - { - currentTarget.Disengage(this); - } - target.Engage(this); - currentTarget = target; - guardTarget = target.Vessel; - } - else - { - if(currentTarget) - { - currentTarget.Disengage(this); - } - guardTarget = null; - currentTarget = null; - } - } - - - - bool SwitchToTurret(float distance) - { - UpdateList(); - - int turretStatus = CheckTurret(distance); - if(turretStatus != 1) - { - CycleWeapon(0); //go to start of array - while(true) - { - CycleWeapon(true); - if(selectedWeapon == null) - { - return false; - } - if(CheckTurret(distance) == 1 && selectedWeapon.GetWeaponClass() != WeaponClasses.DefenseLaser) - { - return true; - } - } - } - else return true; - } - - /* - bool SwitchToRocketTurret(float distance) - { - CycleWeapon(0); - while(true) - { - CycleWeapon(true); - if(selectedWeapon == null) - { - return false; - } - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket && CheckTurret(distance) == 1) - { - return true; - } - } - } - */ - - - bool SwitchToAirMissile() - { - CycleWeapon(0); //go to start of array - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + "Checking air missiles"); - } - - int selectedIndex = 0; - float bestRangeDiff = float.MaxValue; - float targetDistance = Vector3.Distance(guardTarget.transform.position, vessel.transform.position); - - if(weaponArray.Length <= 1) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(" - no weapons"); - } - return false; - } - - for(int i = 1; i < weaponArray.Length; i++) - { - CycleWeapon(i); - - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) - { - foreach(var ml in selectedWeapon.GetPart().FindModulesImplementing()) - { - if(ml.guidanceMode == MissileLauncher.GuidanceModes.AAMLead || ml.guidanceMode == MissileLauncher.GuidanceModes.AAMPure) - { - MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(ml, guardTarget.srf_velocity, guardTarget.transform.position); - if(vessel.srfSpeed > ml.minLaunchSpeed && targetDistance < dlz.maxLaunchRange && targetDistance > dlz.minLaunchRange) - { - float rangeDiff = Mathf.Abs(targetDistance - dlz.rangeTr); - if(rangeDiff < bestRangeDiff) - { - bestRangeDiff = rangeDiff; - selectedIndex = i; - } - } - else - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(" - " + vessel.vesselName + " : " + ml.GetShortName() + " failed DLZ test."); - } - } - //break; - //return true; - } - else - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(" - " + vessel.vesselName + " : " + ml.GetShortName() + " not an AAM."); - } - } - } - } - else - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(" - " + vessel.vesselName + " : " + selectedWeapon.GetShortName() + " not a missile."); - } - } - } - - /* - while(true) - { - CycleWeapon(true); - if(selectedWeapon == null) break;//return false; - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) - { - foreach(var ml in selectedWeapon.GetPart().FindModulesImplementing()) - { - if(ml.guidanceMode == MissileLauncher.GuidanceModes.AAMLead || ml.guidanceMode == MissileLauncher.GuidanceModes.AAMPure) - { - MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(ml, guardTarget.srf_velocity, guardTarget.transform.position); - if(vessel.srfSpeed > ml.minLaunchSpeed && targetDistance < dlz.maxLaunchRange && targetDistance > dlz.minLaunchRange) - { - float rangeDiff = Mathf.Abs(targetDistance - dlz.rangeTr); - if(rangeDiff < bestRangeDiff) - { - bestRangeDiff = rangeDiff; - selectedIndex = weaponIndex; - } - } - else - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(vessel.vesselName + " : " + ml.GetShortName() + " failed DLZ test."); - } - } - break; - //return true; - } - else - { - break; - } - } - } - } - */ - - if(selectedIndex > 0) - { - CycleWeapon(selectedIndex); - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(" - " + vessel.vesselName + " : selecting "+selectedWeapon.GetShortName()); - } - return true; - } - else - { - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(" - " + vessel.vesselName + " : no result."); - } - - return false; - } - } - - bool SwitchToGroundMissile() - { - CycleWeapon(0); //go to start of array - while(true) - { - CycleWeapon(true); - if(selectedWeapon == null) return false; - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) - { - foreach(var ml in selectedWeapon.GetPart().FindModulesImplementing()) - { - if(ml.guidanceMode == MissileLauncher.GuidanceModes.AGM - || ml.guidanceMode == MissileLauncher.GuidanceModes.BeamRiding - || ml.guidanceMode == MissileLauncher.GuidanceModes.STS - || ml.guidanceMode == MissileLauncher.GuidanceModes.Cruise) - { - if(!BDArmorySettings.ALLOW_LEGACY_TARGETING && ml.targetingMode == MissileLauncher.TargetingModes.AntiRad) - { - break; - } - - if(vessel.srfSpeed < ml.minLaunchSpeed) break; - - return true; - } - else - { - break; - } - } - } - } - } - - bool SwitchToBomb() - { - if(vessel.LandedOrSplashed) return false; - - for(int i = 1; i < weaponArray.Length; i++) - { - if(weaponArray[i].GetWeaponClass() == WeaponClasses.Bomb) - { - if(weaponArray[i].GetPart().FindModuleImplementing().targetingMode == MissileLauncher.TargetingModes.GPS) - { - if(targetingPods.Count == 0) - { - continue; - } - } - - CycleWeapon(i); - return true; - } - } - - return false; - } - - bool SwitchToLaser() - { - if(selectedWeapon == null || selectedWeapon.GetWeaponClass() != WeaponClasses.DefenseLaser) - { - CycleWeapon(0); //go to start of array - while(true) - { - CycleWeapon(true); - if(selectedWeapon == null) return false; - if(selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser) return true; - } - } - else return true; - } - - - - int CheckTurret(float distance) - { - if(weaponIndex == 0 || selectedWeapon == null || !(selectedWeapon.GetWeaponClass() == WeaponClasses.Gun || selectedWeapon.GetWeaponClass() == WeaponClasses.DefenseLaser || selectedWeapon.GetWeaponClass()==WeaponClasses.Rocket)) - { - return 2; - } - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Checking turrets"); - } - float finalDistance = distance;//vessel.LandedOrSplashed ? distance : distance/2; //decrease distance requirement if airborne - - if(selectedWeapon.GetWeaponClass() == WeaponClasses.Rocket) - { - foreach(var rl in vessel.FindPartModulesImplementing()) - { - if(rl.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) - { - float gimbalTolerance = vessel.LandedOrSplashed ? 0 : 15; - if(rl.maxTargetingRange >= finalDistance && TargetInTurretRange(rl.turret, gimbalTolerance)) //////check turret limits here - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(selectedWeapon + " is valid!"); - } - return 1; - } - } - } - } - else - { - foreach(var weapon in vessel.FindPartModulesImplementing()) - { - if(weapon.part.partInfo.title == selectedWeapon.GetPart().partInfo.title) - { - float gimbalTolerance = vessel.LandedOrSplashed ? 0 : 15; - if(((!vessel.LandedOrSplashed && pilotAI) || (TargetInTurretRange(weapon.turret, gimbalTolerance))) && weapon.maxEffectiveDistance >= finalDistance) - { - if(weapon.isOverheated) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(selectedWeapon + " is overheated!"); - } - return -1; - } - else if(CheckAmmo(weapon) || BDArmorySettings.INFINITE_AMMO) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(selectedWeapon + " is valid!"); - } - return 1; - } - else - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(selectedWeapon + " has no ammo."); - } - return -1; - } - } - else - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log(selectedWeapon + " can not reach target (" + distance + " vs " + weapon.maxEffectiveDistance + ", yawRange: " + weapon.yawRange + "). Continuing."); - } - } - //else return 0; - } - } - } - return 2; - } - - bool TargetInTurretRange(ModuleTurret turret, float tolerance) - { - if(!turret) - { - return false; - } - - if(!guardTarget) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Checking turret range but no guard target"); - } - return false; - } - if(turret.yawRange == 360) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Checking turret range - turret has full swivel"); - } - return true; - } - - Transform turretTransform = turret.yawTransform.parent; - Vector3 direction = guardTarget.transform.position-turretTransform.position; - Vector3 directionYaw = Vector3.ProjectOnPlane(direction, turretTransform.up); - Vector3 directionPitch = Vector3.ProjectOnPlane(direction, turretTransform.right); - - float angleYaw = Vector3.Angle(turretTransform.forward, directionYaw); - //float anglePitch = Vector3.Angle(-turret.transform.forward, directionPitch); - float signedAnglePitch = Misc.SignedAngle(turretTransform.forward, directionPitch, turretTransform.up); - if(Mathf.Abs(signedAnglePitch) > 90) - { - signedAnglePitch -= Mathf.Sign(signedAnglePitch)*180; - } - bool withinPitchRange = (signedAnglePitch > turret.minPitch && signedAnglePitch < turret.maxPitch); - - if(angleYaw < (turret.yawRange/2)+tolerance && withinPitchRange) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Checking turret range - target is INSIDE gimbal limits! signedAnglePitch: " + signedAnglePitch + ", minPitch: " + turret.minPitch + ", maxPitch: " + turret.maxPitch); - } - return true; - } - else - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Checking turret range - target is OUTSIDE gimbal limits! signedAnglePitch: " + signedAnglePitch + ", minPitch: " + turret.minPitch + ", maxPitch: " + turret.maxPitch + ", angleYaw: " + angleYaw); - } - return false; - } - } - - bool CheckAmmo(ModuleWeapon weapon) - { - string ammoName = weapon.ammoName; - - foreach(Part p in vessel.parts) - { - foreach(var resource in p.Resources.list) - { - if(resource.resourceName == ammoName) - { - if(resource.amount > 0) - { - return true; - } - } - } - } - - return false; - } - - void ToggleTurret() - { - foreach(var weapon in vessel.FindPartModulesImplementing()) - { - if(selectedWeapon == null || weapon.part.partInfo.title != selectedWeapon.GetPart().partInfo.title) - { - weapon.DisableWeapon(); - } - else - { - weapon.EnableWeapon(); - } - } - } - - public void MissileWarning(float distance, MissileLauncher ml)//take distance parameter - { - if(vessel.isActiveVessel && !warningSounding) - { - StartCoroutine(WarningSoundRoutine(distance, ml)); - } - - missileIsIncoming = true; - incomingMissileDistance = distance; - } - - bool warningSounding = false; - IEnumerator WarningSoundRoutine(float distance, MissileLauncher ml)//give distance parameter - { - if(distance < 4000) - { - warningSounding = true; - BDArmorySettings.Instance.missileWarningTime = Time.time; - BDArmorySettings.Instance.missileWarning = true; - warningAudioSource.pitch = distance < 800 ? 1.45f : 1f; - warningAudioSource.PlayOneShot(warningSound); - - float waitTime = distance < 800 ? .25f : 1.5f; - - yield return new WaitForSeconds(waitTime); - - if(ml.vessel && CanSeeTarget(ml.vessel)) - { - BDATargetManager.ReportVessel(ml.vessel, this); - } - } - warningSounding = false; - } - - public void UpdateMaxGuardRange() - { - var rangeEditor = (UI_FloatRange) Fields["guardRange"].uiControlEditor; - if(BDArmorySettings.PHYSICS_RANGE!=0) - { - if(BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - rangeEditor.maxValue = BDArmorySettings.PHYSICS_RANGE; - } - else - { - rangeEditor.maxValue = BDArmorySettings.MAX_GUARD_VISUAL_RANGE; - } - } - else - { - rangeEditor.maxValue = 2500; - } - - } - - bool CheckMouseIsOnGui() - { - return Misc.CheckMouseIsOnGui(); - } - - - bool CheckBombClearance(MissileLauncher ml) - { - if(!BDArmorySettings.BOMB_CLEARANCE_CHECK) return true; - - if(ml.part.ShieldedFromAirstream) - { - /* - foreach(var shield in ml.part.airstreamShields) - { - - if(shield.GetType() == typeof(ModuleCargoBay)) - { - ModuleCargoBay bay = (ModuleCargoBay)shield; - ModuleAnimateGeneric anim = (ModuleAnimateGeneric) bay.part.Modules.GetModule(bay.DeployModuleIndex); - if(anim && anim.Events["Toggle"].guiName == "Close") - { - return true; - } - } - } - */ - return false; - } - - if(ml.rotaryRail && ml.rotaryRail.readyMissile != ml) - { - return false; - } - - if(ml.missileTurret && !ml.missileTurret.turretEnabled) - { - return false; - } - - if(ml.dropTime > 0.3f) - { - //debug lines - LineRenderer lr = null; - if(BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) - { - lr = GetComponent(); - if(!lr) - { - lr = gameObject.AddComponent(); - } - lr.enabled = true; - lr.SetWidth(.1f, .1f); - } - else - { - if(gameObject.GetComponent()) - { - gameObject.GetComponent().enabled = false; - } - } - - - float radius = 0.28f / 2; - float time = ml.dropTime; - Vector3 direction = ((ml.decoupleForward ? ml.missileReferenceTransform.transform.forward : -ml.missileReferenceTransform.transform.up) * ml.decoupleSpeed * time) + ((FlightGlobals.getGeeForceAtPosition(transform.position) - vessel.acceleration) * 0.5f * time*time); - Vector3 crossAxis = Vector3.Cross(direction, ml.missileReferenceTransform.forward).normalized; - - float rayDistance; - if(ml.thrust == 0 || ml.cruiseThrust == 0) - { - rayDistance = 8; - } - else - { - //distance till engine starts based on grav accel and vessel accel - rayDistance = direction.magnitude; - } - - Ray[] rays = new Ray[] { - new Ray(ml.missileReferenceTransform.position - (radius * crossAxis), direction), - new Ray(ml.missileReferenceTransform.position + (radius * crossAxis), direction), - new Ray(ml.missileReferenceTransform.position, direction) - }; - - if(lr) - { - lr.useWorldSpace = false; - lr.SetVertexCount(4); - lr.SetPosition(0, transform.InverseTransformPoint(rays[0].origin)); - lr.SetPosition(1, transform.InverseTransformPoint(rays[0].GetPoint(rayDistance))); - lr.SetPosition(2, transform.InverseTransformPoint(rays[1].GetPoint(rayDistance))); - lr.SetPosition(3, transform.InverseTransformPoint(rays[1].origin)); - } - - for(int i = 0; i < rays.Length; i++) - { - RaycastHit[] hits = Physics.RaycastAll(rays[i], rayDistance, 557057); - for(int h = 0; h < hits.Length; h++) - { - Part p = hits[h].collider.GetComponentInParent(); - - if((p != null && p != ml.part) || p == null) return false; - } - } - - return true; - } - else - { - //forward check for no-drop missiles - if(Physics.Raycast(new Ray(ml.missileReferenceTransform.position, ml.missileReferenceTransform.forward), 50, 557057)) - { - return false; - } - } - - return true; - } - - bool isLegacyCMing = false; - int cmCounter = 0; - int cmAmount = 5; - IEnumerator LegacyCMRoutine() - { - isLegacyCMing = true; - yield return new WaitForSeconds(UnityEngine.Random.Range(.2f, 1f)); - if(incomingMissileDistance < 2500) - { - cmAmount = Mathf.RoundToInt((2500-incomingMissileDistance)/400); - foreach(var cm in vessel.FindPartModulesImplementing()) - { - cm.DropCM(); - } - cmCounter++; - if(cmCounter < cmAmount) - { - yield return new WaitForSeconds(0.15f); - } - else - { - cmCounter = 0; - yield return new WaitForSeconds(UnityEngine.Random.Range(.5f, 1f)); - } - } - isLegacyCMing = false; - } - - public void FireAllCountermeasures(int count) - { - StartCoroutine(AllCMRoutine(count)); - } - - IEnumerator AllCMRoutine(int count) - { - for(int i = 0; i < count; i++) - { - foreach(var cm in vessel.FindPartModulesImplementing()) - { - if((cm.cmType == CMDropper.CountermeasureTypes.Flare && !isFlaring) - || (cm.cmType == CMDropper.CountermeasureTypes.Chaff && !isChaffing) - || (cm.cmType == CMDropper.CountermeasureTypes.Smoke)) - { - cm.DropCM(); - } - } - isFlaring = true; - isChaffing = true; - yield return new WaitForSeconds(1f); - } - isFlaring = false; - isChaffing = false; - } - - - public void FireChaff() - { - if(!isChaffing) - { - StartCoroutine(ChaffRoutine()); - } - } - - public bool isChaffing = false; - IEnumerator ChaffRoutine() - { - isChaffing = true; - yield return new WaitForSeconds(UnityEngine.Random.Range(0.2f, 1f)); - - foreach(var cm in vessel.FindPartModulesImplementing()) - { - if(cm.cmType == CMDropper.CountermeasureTypes.Chaff) - { - cm.DropCM(); - } - } - - yield return new WaitForSeconds(0.6f); - - isChaffing = false; - } - - public bool isFlaring = false; - IEnumerator FlareRoutine(float time) - { - if(isFlaring) yield break; - time = Mathf.Clamp(time, 2, 8); - isFlaring = true; - yield return new WaitForSeconds(UnityEngine.Random.Range(0f, 1f)); - float flareStartTime = Time.time; - while(Time.time - flareStartTime < time) - { - foreach(var cm in vessel.FindPartModulesImplementing()) - { - if(cm.cmType == CMDropper.CountermeasureTypes.Flare) - { - cm.DropCM(); - } - } - yield return new WaitForSeconds(0.6f); - } - isFlaring = false; - } - - - string GetWeaponName(IBDWeapon weapon) - { - if(weapon == null) - { - return "None"; - } - else - { - return weapon.GetShortName(); - } - } - - //ANTIRADIATION - bool antiRadTargetAcquired = false; - Vector3 antiRadiationTarget; - void SearchForRadarSource() - { - antiRadTargetAcquired = false; - if(rwr && rwr.rwrEnabled) - { - float closestAngle = 360; - MissileLauncher missile = currentMissile; - if(!missile) return; - if(missile.targetingMode != MissileLauncher.TargetingModes.AntiRad) return; - for(int i = 0; i < rwr.pingsData.Length; i++) - { - if(rwr.pingsData[i].exists && (rwr.pingsData[i].signalStrength == 0 || rwr.pingsData[i].signalStrength == 5)) - { - float angle = Vector3.Angle(rwr.pingWorldPositions[i] - missile.transform.position, missile.transform.forward); - if(angle < closestAngle && angle < missile.maxOffBoresight) - { - closestAngle = angle; - antiRadiationTarget = rwr.pingWorldPositions[i]; - antiRadTargetAcquired = true; - } - } - } - } - } - - //LASER LOCKING - bool laserPointDetected = false; - ModuleTargetingCamera foundCam; - void SearchForLaserPoint() - { - MissileLauncher ml = currentMissile; - if(!ml || ml.targetingMode != MissileLauncher.TargetingModes.Laser) - { - return; - } - - foundCam = BDATargetManager.GetLaserTarget(ml, (ml.guidanceMode == MissileLauncher.GuidanceModes.BeamRiding)); - if(foundCam) - { - laserPointDetected = true; - } - else - { - laserPointDetected = false; - } - } - - //HEAT LOCKING - public TargetSignatureData heatTarget = TargetSignatureData.noTarget; - void SearchForHeatTarget() - { - MissileLauncher ml = currentMissile; - if(!ml || ml.targetingMode != MissileLauncher.TargetingModes.Heat) - { - return; - } - - float scanRadius = ml.lockedSensorFOV*2; - float maxOffBoresight = ml.maxOffBoresight*0.85f; - - bool radarSlaved = false; - if(vesselRadarData && vesselRadarData.locked) - { - heatTarget = vesselRadarData.lockedTargetData.targetData; - radarSlaved = true; - } - - Vector3 direction = - heatTarget.exists && Vector3.Angle(heatTarget.position - ml.missileReferenceTransform.position, ml.missileReferenceTransform.forward) < maxOffBoresight ? - heatTarget.predictedPosition - ml.missileReferenceTransform.position - : ml.missileReferenceTransform.forward; - - float heatThresh = radarSlaved ? ml.heatThreshold*0.5f : ml.heatThreshold; - - heatTarget = BDATargetManager.GetHeatTarget(new Ray(ml.missileReferenceTransform.position + (50*ml.missileReferenceTransform.forward), direction), scanRadius, ml.heatThreshold, ml.allAspect); - } - - void ClampVisualRange() - { - if(!BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - guardRange = Mathf.Clamp(guardRange, 0, BDArmorySettings.MAX_GUARD_VISUAL_RANGE); - } - - //UpdateMaxGuardRange(); - } - - void RefreshModules() - { - foreach(var rad in radars) - { - rad.EnsureVesselRadarData(); - if(rad.radarEnabled) - { - rad.EnableRadar(); - } - } - radars = vessel.FindPartModulesImplementing(); - foreach(var rad in radars) - { - rad.EnsureVesselRadarData(); - if(rad.radarEnabled) - { - rad.EnableRadar(); - } - } - jammers = vessel.FindPartModulesImplementing(); - targetingPods = vessel.FindPartModulesImplementing(); - } - - private MissileLauncher GetAsymMissile() - { - if(weaponIndex == 0) return null; - if(weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Bomb || - weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Missile) - { - MissileLauncher firstMl = null; - foreach(var ml in vessel.FindPartModulesImplementing()) - { - if(ml.part.name != weaponArray[weaponIndex].GetPart().name) continue; - - if(firstMl == null) firstMl = ml; - - if(!FindSym(ml.part)) - { - return ml; - } - } - return firstMl; - } - else - { - return null; - } - } - - private MissileLauncher GetRotaryReadyMissile() - { - if(weaponIndex == 0) return null; - if(weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Bomb || - weaponArray[weaponIndex].GetWeaponClass() == WeaponClasses.Missile) - { - if(currentMissile && currentMissile.part.name == weaponArray[weaponIndex].GetPart().name) - { - if(!currentMissile.rotaryRail) - { - return currentMissile; - } - else if(currentMissile.rotaryRail.readyToFire && currentMissile.rotaryRail.readyMissile == currentMissile) - { - return currentMissile; - } - } - - foreach(var ml in vessel.FindPartModulesImplementing()) - { - if(ml.part.name != weaponArray[weaponIndex].GetPart().name) continue; - - if(!ml.rotaryRail) - { - return ml; - } - else if(ml.rotaryRail.readyToFire && ml.rotaryRail.readyMissile.part.name == weaponArray[weaponIndex].GetPart().name) - { - return ml.rotaryRail.readyMissile; - } - } - return null; - } - else - { - return null; - } - } - - - } -} - diff --git a/BahaTurret/MissileGuidance.cs b/BahaTurret/MissileGuidance.cs deleted file mode 100644 index ae02fb3e3..000000000 --- a/BahaTurret/MissileGuidance.cs +++ /dev/null @@ -1,388 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class MissileGuidance - { - - public static Vector3 GetAirToGroundTarget(Vector3 targetPosition, Vessel missileVessel, float descentRatio) - { - Vector3 upDirection = missileVessel.upAxis;//-FlightGlobals.getGeeForceAtPosition(targetPosition).normalized; - Vector3 surfacePos = missileVessel.transform.position + Vector3.Project(targetPosition-missileVessel.transform.position, upDirection); //((float)missileVessel.altitude*upDirection); - Vector3 targetSurfacePos; - - targetSurfacePos = targetPosition; - - float distanceToTarget = Vector3.Distance(surfacePos, targetSurfacePos); - - if(missileVessel.srfSpeed < 75 && missileVessel.verticalSpeed < 10)//gain altitude if launching from stationary - { - return missileVessel.transform.position + (5*missileVessel.transform.forward) + (1 * upDirection); - } - - Vector3 finalTarget = targetPosition +(Mathf.Clamp((distanceToTarget-((float)missileVessel.srfSpeed*descentRatio))*0.22f, 0, 2000) * upDirection); - - - //Debug.Log("Using agm trajectory. " + Time.time); - - return finalTarget; - - } - - public static bool GetBallisticGuidanceTarget(Vector3 targetPosition, Vessel missileVessel, bool direct, out Vector3 finalTarget) - { - Vector3 up = VectorUtils.GetUpDirection(missileVessel.transform.position); - Vector3 forward = Vector3.ProjectOnPlane(targetPosition - missileVessel.transform.position, up); - float speed = (float)missileVessel.srfSpeed; - float sqrSpeed = speed * speed; - float sqrSpeedSqr = sqrSpeed * sqrSpeed; - float g = (float)FlightGlobals.getGeeForceAtPosition(missileVessel.transform.position).magnitude; - float height = FlightGlobals.getAltitudeAtPos(targetPosition)-FlightGlobals.getAltitudeAtPos(missileVessel.transform.position); - float sqrRange = forward.sqrMagnitude; - float range = Mathf.Sqrt(sqrRange); - - float plusOrMinus = direct ? -1 : 1; - - float top = sqrSpeed + (plusOrMinus * Mathf.Sqrt(sqrSpeedSqr - (g * ((g * sqrRange + (2 * height * sqrSpeed)))))); - float bottom = g * range; - float theta = Mathf.Atan(top / bottom); - - if(!float.IsNaN(theta)) - { - Vector3 finalVector = Quaternion.AngleAxis(theta * Mathf.Rad2Deg, Vector3.Cross(forward, up)) * forward; - finalTarget = missileVessel.transform.position + (100 * finalVector); - return true; - } - else - { - finalTarget = Vector3.zero; - return false; - } - } - - public static bool GetBallisticGuidanceTarget(Vector3 targetPosition, Vector3 missilePosition, float missileSpeed, bool direct, out Vector3 finalTarget) - { - Vector3 up = VectorUtils.GetUpDirection(missilePosition); - Vector3 forward = Vector3.ProjectOnPlane(targetPosition - missilePosition, up); - float speed = missileSpeed; - float sqrSpeed = speed * speed; - float sqrSpeedSqr = sqrSpeed * sqrSpeed; - float g = (float)FlightGlobals.getGeeForceAtPosition(missilePosition).magnitude; - float height = FlightGlobals.getAltitudeAtPos(targetPosition)-FlightGlobals.getAltitudeAtPos(missilePosition); - float sqrRange = forward.sqrMagnitude; - float range = Mathf.Sqrt(sqrRange); - - float plusOrMinus = direct ? -1 : 1; - - float top = sqrSpeed + (plusOrMinus * Mathf.Sqrt(sqrSpeedSqr - (g * ((g * sqrRange + (2 * height * sqrSpeed)))))); - float bottom = g * range; - float theta = Mathf.Atan(top / bottom); - - if(!float.IsNaN(theta)) - { - Vector3 finalVector = Quaternion.AngleAxis(theta * Mathf.Rad2Deg, Vector3.Cross(forward, up)) * forward; - finalTarget = missilePosition + (100 * finalVector); - return true; - } - else - { - finalTarget = Vector3.zero; - return false; - } - } - - public static Vector3 GetBeamRideTarget(Ray beam, Vector3 currentPosition, Vector3 currentVelocity, float correctionFactor, float correctionDamping, Ray previousBeam) - { - float onBeamDistance = Vector3.Project(currentPosition - beam.origin, beam.direction).magnitude; - //Vector3 onBeamPos = beam.origin+Vector3.Project(currentPosition-beam.origin, beam.direction);//beam.GetPoint(Vector3.Distance(Vector3.Project(currentPosition-beam.origin, beam.direction), Vector3.zero)); - Vector3 onBeamPos = beam.GetPoint(onBeamDistance); - Vector3 previousBeamPos = previousBeam.GetPoint(onBeamDistance); - Vector3 beamVel = (onBeamPos - previousBeamPos) / Time.fixedDeltaTime; - Vector3 target = onBeamPos + (500f * beam.direction); - Vector3 offset = onBeamPos - currentPosition; - offset += beamVel*0.5f; - target += correctionFactor * offset; - - Vector3 velDamp = correctionDamping * Vector3.ProjectOnPlane(currentVelocity-beamVel, beam.direction); - target -= velDamp; - - - return target; - } - - public static Vector3 GetAirToAirTarget(Vector3 targetPosition, Vector3 targetVelocity, Vector3 targetAcceleration, Vessel missileVessel, out float timeToImpact, float minSpeed = 200) - { - float leadTime = 0; - float targetDistance = Vector3.Distance(targetPosition, missileVessel.transform.position); - - Vector3 currVel = Mathf.Max((float)missileVessel.srfSpeed, minSpeed) * missileVessel.srf_velocity.normalized; - - leadTime = (float)(1/((targetVelocity-currVel).magnitude/targetDistance)); - timeToImpact = leadTime; - leadTime = Mathf.Clamp(leadTime, 0f, 8f); - Vector3 mTargetPosition = targetPosition + (targetVelocity*leadTime); - - if(targetDistance < 1600) - { - //mTargetPosition += (Vector3)targetAcceleration * 0.03f * Mathf.Pow(leadTime,2); - } - - - - if(targetDistance > 500) - { - Vector3 upDirection = -FlightGlobals.getGeeForceAtPosition(targetPosition).normalized; - float targetAltitude = FlightGlobals.getAltitudeAtPos(targetPosition); - targetPosition += Mathf.Clamp((float)(targetAltitude-missileVessel.altitude)/6, -20, 1500)*upDirection; - } - - Vector3 finalTarget = mTargetPosition; - - return finalTarget; - } - - public static Vector3 GetAirToAirFireSolution(MissileLauncher missile, Vessel targetVessel) - { - if(!targetVessel) - { - return missile.transform.position + (missile.transform.forward*1000); - } - Vector3 targetPosition = targetVessel.transform.position; - float leadTime = 0; - float targetDistance = Vector3.Distance(targetVessel.transform.position, missile.transform.position); - - Vector3 simMissileVel = missile.optimumAirspeed * (targetPosition-missile.transform.position).normalized; - leadTime = targetDistance/(float)(targetVessel.srf_velocity-simMissileVel).magnitude; - leadTime = Mathf.Clamp (leadTime, 0f, 8f); - targetPosition = targetPosition + (targetVessel.srf_velocity*leadTime); - - if(targetVessel && targetDistance < 800) - { - targetPosition += (Vector3)targetVessel.acceleration * 0.05f * leadTime * leadTime; - } - - return targetPosition; - } - - public static Vector3 GetAirToAirFireSolution(MissileLauncher missile, Vector3 targetPosition, Vector3 targetVelocity) - { - float leadTime = 0; - float targetDistance = Vector3.Distance(targetPosition, missile.transform.position); - - Vector3 simMissileVel = missile.optimumAirspeed * (targetPosition-missile.transform.position).normalized; - leadTime = targetDistance/(targetVelocity-simMissileVel).magnitude; - leadTime = Mathf.Clamp (leadTime, 0f, 8f); - - targetPosition = targetPosition + (targetVelocity*leadTime); - - return targetPosition; - } - - public static Vector3 GetCruiseTarget(Vector3 targetPosition, Vessel missileVessel, float radarAlt) - { - Vector3 upDirection = VectorUtils.GetUpDirection(missileVessel.transform.position); - float currentRadarAlt = GetRadarAltitude(missileVessel); - float distanceSqr = (targetPosition - (missileVessel.transform.position - (currentRadarAlt * upDirection))).sqrMagnitude; - - - Vector3 planarDirectionToTarget = Vector3.ProjectOnPlane(targetPosition - missileVessel.transform.position, upDirection).normalized; - - /* - if(missileVessel.srfSpeed < 1 && missileVessel.verticalSpeed < 1) //gain altitude if launching from stationary - { - return missileVessel.transform.position + (5 * missileVessel.transform.forward) + (40 * upDirection); - } - */ - - float error; - - if(currentRadarAlt > 1600) - { - error = 500000; - } - else - { - Vector3 tRayDirection = (planarDirectionToTarget * 10) - (10 * upDirection); - Ray terrainRay = new Ray(missileVessel.transform.position, tRayDirection); - RaycastHit rayHit; - if(Physics.Raycast(terrainRay, out rayHit, 8000, 1 << 15)) - { - float detectedAlt = Vector3.Project(rayHit.point - missileVessel.transform.position, upDirection).magnitude; - - error = Mathf.Min(detectedAlt, currentRadarAlt) - radarAlt; - } - else - { - error = currentRadarAlt - radarAlt; - } - } - - error = Mathf.Clamp(0.05f * error, -5, 3); - return missileVessel.transform.position + (10 * planarDirectionToTarget) - (error * upDirection); - } - - public static Vector3 GetTerminalManeuveringTarget(Vector3 targetPosition, Vessel missileVessel, float radarAlt) - { - Vector3 upDirection = -FlightGlobals.getGeeForceAtPosition(missileVessel.GetWorldPos3D()).normalized; - Vector3 planarVectorToTarget = Vector3.ProjectOnPlane(targetPosition - missileVessel.transform.position, upDirection); - Vector3 planarDirectionToTarget = planarVectorToTarget.normalized; - Vector3 crossAxis = Vector3.Cross(planarDirectionToTarget, upDirection).normalized; - float sinAmplitude = Mathf.Clamp(Vector3.Distance(targetPosition, missileVessel.transform.position)-850, 0, 4500); - Vector3 sinOffset = (Mathf.Sin(1.25f * Time.time) * sinAmplitude * crossAxis); - Vector3 targetSin = targetPosition + sinOffset; - Vector3 planarSin = missileVessel.transform.position + planarVectorToTarget + sinOffset; - - Vector3 finalTarget; - if(Vector3.Distance(targetPosition,missileVessel.transform.position) > (2500+GetRadarAltitude(missileVessel))) - { - finalTarget = targetPosition; - } - else if(!GetBallisticGuidanceTarget(targetSin, missileVessel, true, out finalTarget)) - { - //finalTarget = GetAirToGroundTarget(targetSin, missileVessel, 6); - finalTarget = planarSin; - } - return finalTarget; - } - - - public static FloatCurve DefaultLiftCurve = null; - public static FloatCurve DefaultDragCurve = null; - public static Vector3 DoAeroForces(MissileLauncher ml, Vector3 targetPosition, float liftArea, float steerMult, Vector3 previousTorque, float maxTorque, float maxAoA) - { - if(DefaultLiftCurve == null) - { - DefaultLiftCurve = new FloatCurve(); - DefaultLiftCurve.Add(0, 0); - DefaultLiftCurve.Add(8, .35f); - // DefaultLiftCurve.Add(19, 1); - // DefaultLiftCurve.Add(23, .9f); - DefaultLiftCurve.Add(30, 1.5f); - DefaultLiftCurve.Add(65, .6f); - DefaultLiftCurve.Add(90, .7f); - } - - if(DefaultDragCurve == null) - { - DefaultDragCurve = new FloatCurve(); - DefaultDragCurve.Add(0, 0.00215f); - DefaultDragCurve.Add(5, .00285f); - DefaultDragCurve.Add(15, .007f); - DefaultDragCurve.Add(29, .01f); - DefaultDragCurve.Add(55, .3f); - DefaultDragCurve.Add(90, .5f); - } - - - FloatCurve liftCurve = DefaultLiftCurve; - FloatCurve dragCurve = DefaultDragCurve; - - return DoAeroForces(ml, targetPosition, liftArea, steerMult, previousTorque, maxTorque, maxAoA, liftCurve, dragCurve); - } - - public static Vector3 DoAeroForces(MissileLauncher ml, Vector3 targetPosition, float liftArea, float steerMult, Vector3 previousTorque, float maxTorque, float maxAoA, FloatCurve liftCurve, FloatCurve dragCurve) - { - Rigidbody rb = ml.part.rb; - double airDensity = ml.vessel.atmDensity; - double airSpeed = ml.vessel.srfSpeed; - Vector3d velocity = ml.vessel.srf_velocity; - - //temp values - Vector3 CoL = new Vector3(0, 0, -1f); - float liftMultiplier = BDArmorySettings.GLOBAL_LIFT_MULTIPLIER; - float dragMultiplier = BDArmorySettings.GLOBAL_DRAG_MULTIPLIER; - - - //lift - float AoA = Mathf.Clamp(Vector3.Angle(ml.transform.forward, velocity.normalized), 0, 90); - if(AoA > 0) - { - double liftForce = 0.5 * airDensity * Math.Pow(airSpeed, 2) * liftArea * liftMultiplier * liftCurve.Evaluate(AoA); - Vector3 forceDirection = Vector3.ProjectOnPlane(-velocity, ml.transform.forward).normalized; - rb.AddForceAtPosition((float)liftForce * forceDirection, ml.transform.TransformPoint(ml.part.CoMOffset+CoL)); - } - - //drag - if(airSpeed > 0) - { - double dragForce = 0.5 * airDensity * Math.Pow(airSpeed, 2) * liftArea * dragMultiplier * dragCurve.Evaluate(AoA); - rb.AddForceAtPosition((float)dragForce * -velocity.normalized, ml.transform.TransformPoint(ml.part.CoMOffset+CoL)); - } - - - //guidance - if(airSpeed > 1) - { - Vector3 targetDirection; - float targetAngle; - if(AoA < maxAoA) - { - targetDirection = (targetPosition - ml.transform.position); - targetAngle = Vector3.Angle(velocity.normalized, targetDirection) * 4; - } - else - { - targetDirection = velocity.normalized; - targetAngle = AoA; - } - - Vector3 torqueDirection = -Vector3.Cross(targetDirection, velocity.normalized).normalized; - torqueDirection = ml.transform.InverseTransformDirection(torqueDirection); - - float torque = Mathf.Clamp(targetAngle * steerMult, 0, maxTorque); - Vector3 finalTorque = Vector3.ProjectOnPlane(Vector3.Lerp(previousTorque, torqueDirection*torque, 1), Vector3.forward); - - rb.AddRelativeTorque(finalTorque); - - return finalTorque; - - } - else - { - Vector3 finalTorque = Vector3.ProjectOnPlane(Vector3.Lerp(previousTorque, Vector3.zero, 0.25f), Vector3.forward); - rb.AddRelativeTorque(finalTorque); - return finalTorque; - } - } - - public static float GetRadarAltitude(Vessel vessel) - { - float radarAlt = Mathf.Clamp((float)(vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass())-vessel.terrainAltitude), 0, (float)vessel.altitude); - return radarAlt; - } - - public static float GetRaycastRadarAltitude(Vector3 position) - { - Vector3 upDirection = -FlightGlobals.getGeeForceAtPosition(position).normalized; - - float altAtPos = FlightGlobals.getAltitudeAtPos(position); - if(altAtPos < 0) - { - position += 2 * Mathf.Abs(altAtPos) * upDirection; - } - - Ray ray = new Ray(position, -upDirection); - float rayDistance = FlightGlobals.getAltitudeAtPos(position); - - if(rayDistance < 0) - { - return 0; - } - - RaycastHit rayHit; - if(Physics.Raycast(ray, out rayHit, rayDistance, 1<<15)) - { - return rayHit.distance; - } - else - { - return rayDistance; - } - } - - - } -} - diff --git a/BahaTurret/MissileLaunchParams.cs b/BahaTurret/MissileLaunchParams.cs deleted file mode 100644 index fa54ae3e5..000000000 --- a/BahaTurret/MissileLaunchParams.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public struct MissileLaunchParams - { - public float minLaunchRange; - public float maxLaunchRange; - - private float rtr; - /// - /// Gets the maximum no-escape range. - /// - /// The max no-escape range. - public float rangeTr - { - get - { - return rtr; - } - } - - - public MissileLaunchParams(float min, float max) - { - minLaunchRange = min; - maxLaunchRange = max; - rtr = (max + min) / 2; - } - - /// - /// Gets the dynamic launch parameters. - /// - /// The dynamic launch parameters. - /// Launcher velocity. - /// Target velocity. - public static MissileLaunchParams GetDynamicLaunchParams(MissileLauncher missile, Vector3 targetVelocity, Vector3 targetPosition) - { - Vector3 launcherVelocity = missile.vessel.srf_velocity; - float launcherSpeed = (float)missile.vessel.srfSpeed; - float minLaunchRange = missile.minStaticLaunchRange; - float maxLaunchRange = missile.maxStaticLaunchRange; - - float rangeAddMin = 0; - float rangeAddMax = 0; - float relSpeed; - - Vector3 relV = targetVelocity - launcherVelocity; - Vector3 vectorToTarget = targetPosition - missile.part.transform.position; - Vector3 relVProjected = Vector3.Project(relV, vectorToTarget); - relSpeed = -Mathf.Sign(Vector3.Dot(relVProjected, vectorToTarget)) * relVProjected.magnitude; - - - rangeAddMin += relSpeed * 2; - rangeAddMax += relSpeed * 8; - rangeAddMin += launcherSpeed * 2; - rangeAddMax += launcherSpeed * 2; - - double diffAlt = missile.vessel.altitude - FlightGlobals.getAltitudeAtPos(targetPosition); - - rangeAddMax += (float)diffAlt; - - float min = Mathf.Clamp(minLaunchRange + rangeAddMin, 0, 20000); - float max = Mathf.Clamp(maxLaunchRange + rangeAddMax, min+100, 20000); - - return new MissileLaunchParams(min, max); - } - - - } -} - diff --git a/BahaTurret/MissileLauncher.cs b/BahaTurret/MissileLauncher.cs deleted file mode 100644 index 7709a6387..000000000 --- a/BahaTurret/MissileLauncher.cs +++ /dev/null @@ -1,2374 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - - -namespace BahaTurret -{ - - - public class MissileLauncher : PartModule, IBDWeapon - { - public enum MissileStates{Idle, Drop, Boost, Cruise, PostThrust} - - public Transform missileReferenceTransform; - - public enum GuidanceModes{None,AAMLead,AAMPure,AGM,AGMBallistic,Cruise,STS,Bomb,RCS, BeamRiding} - public GuidanceModes guidanceMode; - [KSPField] - public string homingType = "AAM"; - - [KSPField] - public string targetingType = "none"; - public enum TargetingModes{None,Radar,Heat,Laser,GPS,AntiRad} - public TargetingModes targetingMode; - public bool team; - - public float timeFired = -1; - public float timeIndex = 0; - - public MissileTurret missileTurret = null; - public BDRotaryRail rotaryRail = null; - - [KSPField] - public string exhaustPrefabPath; - - [KSPField] - public string boostExhaustPrefabPath; - - [KSPField] - public string boostExhaustTransformName; - - //aero - [KSPField] - public bool aero = false; - [KSPField] - public float liftArea = 0.015f; - [KSPField] - public float steerMult = 0.5f; - [KSPField] - public float torqueRampUp = 30f; - Vector3 aeroTorque = Vector3.zero; - float controlAuthority = 0; - float finalMaxTorque = 0; - [KSPField] - public float aeroSteerDamping = 0; - - [KSPField] - public float maxTorque = 90; - // - - [KSPField] - public float thrust = 30; - [KSPField] - public float cruiseThrust = 3; - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Drop Time"), - UI_FloatRange(minValue = 0f, maxValue = 2f, stepIncrement = 0.1f, scene = UI_Scene.Editor)] - public float dropTime = 0.4f; - [KSPField] - public float boostTime = 2.2f; - [KSPField] - public float cruiseTime = 45; - [KSPField] - public float cruiseDelay = 0; - [KSPField] - public bool guidanceActive = true; - [KSPField] - public float maxOffBoresight = 45; - - [KSPField] - public float maxAoA = 35; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Decouple Speed"), - UI_FloatRange(minValue = 0f, maxValue = 10f, stepIncrement = 0.5f, scene = UI_Scene.Editor)] - public float decoupleSpeed = 0; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "Direction: "), - UI_Toggle(disabledText = "Lateral", enabledText = "Forward")] - public bool decoupleForward = false; - - - - [KSPField] - public float optimumAirspeed = 220; - - [KSPField] - public float blastRadius = 150; - [KSPField] - public float blastPower = 25; - [KSPField] - public float blastHeat = -1; - [KSPField] - public float maxTurnRateDPS = 20; - [KSPField] - public bool proxyDetonate = true; - - [KSPField] - public string audioClipPath = string.Empty; - - AudioClip thrustAudio; - - [KSPField] - public string boostClipPath = string.Empty; - - AudioClip boostAudio; - - [KSPField] - public bool isSeismicCharge = false; - - [KSPField] - public float rndAngVel = 0; - - [KSPField] - public bool isTimed = false; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = false, guiName = "Detonation Time"), - UI_FloatRange(minValue = 2f, maxValue = 30f, stepIncrement = 0.5f, scene = UI_Scene.Editor)] - public float detonationTime = 2; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Cruise Altitude"), - UI_FloatRange(minValue = 30, maxValue = 2500f, stepIncrement = 5f, scene = UI_Scene.All)] - public float cruiseAltitude = 500; - - [KSPField] - public string rotationTransformName = string.Empty; - Transform rotationTransform; - - [KSPField] - public bool terminalManeuvering = false; - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "In Cargo Bay: "), - UI_Toggle(disabledText = "False", enabledText = "True", affectSymCounterparts = UI_Scene.All)] - public bool inCargoBay = false; - - - [KSPField] - public string explModelPath = "BDArmory/Models/explosion/explosion"; - - public string explSoundPath = "BDArmory/Sounds/explode1"; - - - [KSPField] - public bool spoolEngine = false; - - [KSPField] - public bool hasRCS = false; - [KSPField] - public float rcsThrust = 1; - float rcsRVelThreshold = 0.13f; - KSPParticleEmitter upRCS; - KSPParticleEmitter downRCS; - KSPParticleEmitter leftRCS; - KSPParticleEmitter rightRCS; - KSPParticleEmitter forwardRCS; - float rcsAudioMinInterval = 0.2f; - - public Vessel sourceVessel = null; - bool checkMiss = false; - bool hasExploded = false; - private AudioSource audioSource; - public AudioSource sfAudioSource; - List pEmitters; - List gaplessEmitters; - - public MissileFire targetMf = null; - public bool hasFired = false; - - - LineRenderer LR; - float cmTimer; - - //deploy animation - [KSPField] - public string deployAnimationName = ""; - - [KSPField] - public float deployedDrag = 0.02f; - - [KSPField] - public float deployTime = 0.2f; - - [KSPField] - public bool useSimpleDrag = false; - [KSPField] - public float simpleDrag = 0.02f; - [KSPField] - public float simpleStableTorque = 5; - - [KSPField] - public Vector3 simpleCoD = new Vector3(0,0,-1); - - [KSPField] - public float agmDescentRatio = 1.45f; - - float currentThrust = 0; - - public bool deployed; - //public float deployedTime; - - AnimationState[] deployStates; - - bool hasPlayedFlyby = false; - - float debugTurnRate = 0; - string debugString = ""; - - - List boosters; - [KSPField] - public bool decoupleBoosters = false; - [KSPField] - public float boosterDecoupleSpeed = 5; - [KSPField] - public float boosterMass = 0; - - public float timeToImpact; - public bool targetAcquired = false; - public Vector3 targetPosition = Vector3.zero; - Vector3 targetVelocity = Vector3.zero; - Vector3 targetAcceleration = Vector3.zero; - - public Vessel legacyTargetVessel; - - - Transform vesselReferenceTransform; - - [KSPField] - public string boostTransformName = string.Empty; - List boostEmitters; - List boostGaplessEmitters; - - public MissileStates MissileState = MissileStates.Idle; - - [KSPField] - public float lockedSensorFOV = 2.5f; - - - //laser stuff - public ModuleTargetingCamera lockedCamera = null; - Vector3 lastLaserPoint; - Vector3 laserStartPosition; - Vector3 startDirection; - - - //heat stuff - public TargetSignatureData heatTarget; - [KSPField] - public float heatThreshold = 200; - [KSPField] - public bool allAspect = false; - - - - float lockFailTimer = -1; - public bool hasMissed = false; - - //radar stuff - //public ModuleRadar radar; - public VesselRadarData vrd; - public TargetSignatureData radarTarget; - [KSPField] - public float activeRadarRange = 6000; - public bool activeRadar = false; - float lastRWRPing = 0; - [KSPField] - public float activeRadarMinThresh = 140; - [KSPField] - public bool radarLOAL = false; - bool radarLOALSearching = false; - - //GPS stuff - public Vector3d targetGPSCoords; - - - //torpedo - [KSPField] - public bool torpedo = false; - [KSPField] - public float waterImpactTolerance = 25; - - - //weapon interface - [KSPField] - public string missileType = "missile"; - private WeaponClasses weaponClass; - public WeaponClasses GetWeaponClass() - { - return weaponClass; - } - void ParseWeaponClass() - { - missileType = missileType.ToLower(); - if(missileType == "bomb") - { - weaponClass = WeaponClasses.Bomb; - } - else - { - weaponClass = WeaponClasses.Missile; - } - } - [KSPField] - public string shortName = string.Empty; - public string GetShortName() - { - return shortName; - } - public Part GetPart() - { - return part; - } - string tModeString; - public string GetSubLabel() - { - if(tModeString == "None") - { - return string.Empty; - } - else - { - return tModeString; - } - } - - //firing paramters - [KSPField] - public float minLaunchSpeed = 0; //only used by AI - [KSPField] - public float minStaticLaunchRange = 10; - [KSPField] - public float maxStaticLaunchRange = 3000; - - - //ballistic options - [KSPField] - public bool indirect = false; - - public override void OnStart(PartModule.StartState state) - { - ParseWeaponClass(); - - if(shortName == string.Empty) - { - shortName = part.partInfo.title; - } - - gaplessEmitters = new List(); - pEmitters = new List(); - boostEmitters = new List(); - boostGaplessEmitters = new List(); - - if(isTimed) - { - Fields["detonationTime"].guiActive = true; - Fields["detonationTime"].guiActiveEditor = true; - } - else - { - Fields["detonationTime"].guiActive = false; - Fields["detonationTime"].guiActiveEditor = false; - } - - ParseModes(); - - foreach(var emitter in part.FindModelComponents()) - { - emitter.emit = false; - } - - if(HighLogic.LoadedSceneIsFlight) - { - missileReferenceTransform = part.FindModelTransform("missileTransform"); - if(!missileReferenceTransform) - { - missileReferenceTransform = part.partTransform; - } - - if(!string.IsNullOrEmpty(exhaustPrefabPath)) - { - foreach(var t in part.FindModelTransforms("exhaustTransform")) - { - GameObject exhaustPrefab = (GameObject)Instantiate(GameDatabase.Instance.GetModel(exhaustPrefabPath)); - exhaustPrefab.SetActive(true); - foreach(var emitter in exhaustPrefab.GetComponentsInChildren()) - { - emitter.emit = false; - } - exhaustPrefab.transform.parent = t; - exhaustPrefab.transform.localPosition = Vector3.zero; - exhaustPrefab.transform.localRotation = Quaternion.identity; - } - } - - if(!string.IsNullOrEmpty(boostExhaustPrefabPath) && !string.IsNullOrEmpty(boostExhaustTransformName)) - { - foreach(var t in part.FindModelTransforms(boostExhaustTransformName)) - { - GameObject exhaustPrefab = (GameObject)Instantiate(GameDatabase.Instance.GetModel(boostExhaustPrefabPath)); - exhaustPrefab.SetActive(true); - foreach(var emitter in exhaustPrefab.GetComponentsInChildren()) - { - emitter.emit = false; - } - exhaustPrefab.transform.parent = t; - exhaustPrefab.transform.localPosition = Vector3.zero; - exhaustPrefab.transform.localRotation = Quaternion.identity; - } - } - - - boosters = new List(); - if(!string.IsNullOrEmpty(boostTransformName)) - { - foreach(var t in part.FindModelTransforms(boostTransformName)) - { - boosters.Add(t.gameObject); - - foreach(var be in t.GetComponentsInChildren()) - { - if(be.useWorldSpace) - { - if(!be.GetComponent()) - { - BDAGaplessParticleEmitter ge = be.gameObject.AddComponent(); - ge.part = part; - boostGaplessEmitters.Add(ge); - } - } - else - { - if(!boostEmitters.Contains(be)) - { - boostEmitters.Add(be); - } - } - } - } - } - - foreach(var emitter in part.partTransform.FindChild("model").GetComponentsInChildren()) - { - if(emitter.GetComponent() || boostEmitters.Contains(emitter)) - { - continue; - } - - if(emitter.useWorldSpace) - { - BDAGaplessParticleEmitter gaplessEmitter = emitter.gameObject.AddComponent(); - gaplessEmitter.part = part; - gaplessEmitters.Add (gaplessEmitter); - } - else - { - if(emitter.transform.name != boostTransformName) - { - pEmitters.Add(emitter); - } - else - { - boostEmitters.Add(emitter); - } - } - } - - cmTimer = Time.time; - - part.force_activate(); - - - - foreach(var pe in pEmitters) - { - if(hasRCS) - { - if(pe.gameObject.name == "rcsUp") upRCS = pe; - else if(pe.gameObject.name == "rcsDown") downRCS = pe; - else if(pe.gameObject.name == "rcsLeft") leftRCS = pe; - else if(pe.gameObject.name == "rcsRight") rightRCS = pe; - else if(pe.gameObject.name == "rcsForward") forwardRCS = pe; - } - - if(!pe.gameObject.name.Contains("rcs") && !pe.useWorldSpace) - { - pe.sizeGrow = 99999; - } - } - - if(rotationTransformName!=string.Empty) - { - rotationTransform = part.FindModelTransform(rotationTransformName); - } - - - - - - - - if(hasRCS) - { - SetupRCS(); - KillRCS(); - } - - SetupAudio(); - - - - } - - if(guidanceMode != GuidanceModes.Cruise) - { - Fields["cruiseAltitude"].guiActive = false; - Fields["cruiseAltitude"].guiActiveEditor = false; - } - - if(part.partInfo.title.Contains("Bomb")) - { - Fields["dropTime"].guiActive = false; - Fields["dropTime"].guiActiveEditor = false; - } - - if(deployAnimationName != "") - { - deployStates = Misc.SetUpAnimation(deployAnimationName, part); - } - else - { - deployedDrag = simpleDrag; - } - } - - /* - void OnCollisionEnter(Collision col) - { - if(!hasExploded && hasFired && Time.time - timeFired > 1) - { - Detonate(); - } - } - */ - - void SetupAudio() - { - audioSource = gameObject.AddComponent(); - audioSource.minDistance = 1; - audioSource.maxDistance = 1000; - audioSource.loop = true; - audioSource.pitch = 1f; - audioSource.priority = 255; - audioSource.spatialBlend = 1; - - if(audioClipPath!=string.Empty) - { - audioSource.clip = GameDatabase.Instance.GetAudioClip(audioClipPath); - } - - sfAudioSource = gameObject.AddComponent(); - sfAudioSource.minDistance = 1; - sfAudioSource.maxDistance = 2000; - sfAudioSource.dopplerLevel = 0; - sfAudioSource.priority = 230; - sfAudioSource.spatialBlend = 1; - - - - if(audioClipPath != string.Empty) - { - thrustAudio = GameDatabase.Instance.GetAudioClip(audioClipPath); - } - - if(boostClipPath != string.Empty) - { - boostAudio = GameDatabase.Instance.GetAudioClip(boostClipPath); - } - - UpdateVolume(); - BDArmorySettings.OnVolumeChange += UpdateVolume; - } - - void UpdateVolume() - { - if(audioSource) - { - audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - } - if(sfAudioSource) - { - sfAudioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - } - } - - void OnDestroy() - { - BDArmorySettings.OnVolumeChange -= UpdateVolume; - } - - [KSPAction("Fire Missile")] - public void AGFire(KSPActionParam param) - { - if(BDArmorySettings.Instance.ActiveWeaponManager != null && BDArmorySettings.Instance.ActiveWeaponManager.vessel == vessel) BDArmorySettings.Instance.ActiveWeaponManager.SendTargetDataToMissile(this); - if(missileTurret) - { - missileTurret.FireMissile(this); - } - else if(rotaryRail) - { - rotaryRail.FireMissile(this); - } - else - { - FireMissile(); - } - if(BDArmorySettings.Instance.ActiveWeaponManager!=null) BDArmorySettings.Instance.ActiveWeaponManager.UpdateList(); - } - - [KSPEvent(guiActive = true, guiName = "Fire Missile", active = true)] - public void GuiFire() - { - if(BDArmorySettings.Instance.ActiveWeaponManager != null && BDArmorySettings.Instance.ActiveWeaponManager.vessel == vessel) BDArmorySettings.Instance.ActiveWeaponManager.SendTargetDataToMissile(this); - if(missileTurret) - { - missileTurret.FireMissile(this); - } - else if(rotaryRail) - { - rotaryRail.FireMissile(this); - } - else - { - FireMissile(); - } - if(BDArmorySettings.Instance.ActiveWeaponManager!=null) BDArmorySettings.Instance.ActiveWeaponManager.UpdateList(); - } - - [KSPEvent(guiActive = true, guiActiveEditor = false, active = true, guiName = "Jettison")] - public void Jettison() - { - if(missileTurret) return; - - part.decouple(0); - if(BDArmorySettings.Instance.ActiveWeaponManager!=null) BDArmorySettings.Instance.ActiveWeaponManager.UpdateList(); - } - - - public void FireMissile() - { - if(!hasFired) - { - - - hasFired = true; - - GameEvents.onPartDie.Add(PartDie); - - BDATargetManager.FiredMissiles.Add(this); - - if(GetComponentInChildren()) - { - BDArmorySettings.numberOfParticleEmitters++; - } - - foreach(var wpm in vessel.FindPartModulesImplementing()) - { - team = wpm.team; - break; - } - - sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/deployClick")); - - sourceVessel = vessel; - - - - //TARGETING - targetPosition = transform.position + (transform.forward * 5000); //set initial target position so if no target update, missile will count a miss if it nears this point or is flying post-thrust - startDirection = transform.forward; - if(BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - if(vessel.targetObject!=null && vessel.targetObject.GetVessel()!=null) - { - legacyTargetVessel = vessel.targetObject.GetVessel(); - - foreach(var mf in legacyTargetVessel.FindPartModulesImplementing()) - { - targetMf = mf; - break; - } - - if(targetingMode == TargetingModes.Heat) - { - heatTarget = new TargetSignatureData(legacyTargetVessel, 9999); - } - } - } - if(targetingMode == TargetingModes.Laser) - { - laserStartPosition = transform.position; - if(lockedCamera) - { - targetAcquired = true; - targetPosition = lastLaserPoint = lockedCamera.groundTargetPosition; - targetingPod = lockedCamera; - } - } - else if(targetingMode == TargetingModes.AntiRad && targetAcquired) - { - RadarWarningReceiver.OnRadarPing += ReceiveRadarPing; - } - - part.decouple(0); - part.force_activate(); - part.Unpack(); - vessel.situation = Vessel.Situations.FLYING; - part.rb.isKinematic = false; - BDArmorySettings.Instance.ApplyNewVesselRanges(vessel); - part.bodyLiftMultiplier = 0; - part.dragModel = Part.DragModel.NONE; - - //add target info to vessel - TargetInfo info = vessel.gameObject.AddComponent(); - info.team = BDATargetManager.BoolToTeam(team); - info.isMissile = true; - info.missileModule = this; - - StartCoroutine(DecoupleRoutine()); - - - - - vessel.vesselName = GetShortName(); - vessel.vesselType = VesselType.Probe; - - - timeFired = Time.time; - - - //setting ref transform for navball - GameObject refObject = new GameObject(); - refObject.transform.rotation = Quaternion.LookRotation(-transform.up, transform.forward); - refObject.transform.parent = transform; - part.SetReferenceTransform(refObject.transform); - vessel.SetReferenceTransform(part); - vesselReferenceTransform = refObject.transform; - - MissileState = MissileStates.Drop; - - part.crashTolerance = 9999; - - - StartCoroutine(MissileRoutine()); - - } - } - - IEnumerator DecoupleRoutine() - { - yield return new WaitForFixedUpdate(); - - if(rndAngVel > 0) - { - part.rb.angularVelocity += UnityEngine.Random.insideUnitSphere.normalized * rndAngVel; - } - - - if(decoupleForward) - { - part.rb.velocity += decoupleSpeed * part.transform.forward; - } - else - { - part.rb.velocity += decoupleSpeed * -part.transform.up; - } - - } - - /// - /// Fires the missile on target vessel. Used by AI currently. - /// - /// V. - public void FireMissileOnTarget(Vessel v) - { - if(!hasFired) - { - legacyTargetVessel = v; - - FireMissile(); - } - } - - void OnDisable() - { - if(targetingMode == TargetingModes.AntiRad) - { - RadarWarningReceiver.OnRadarPing -= ReceiveRadarPing; - } - } - - - public override void OnFixedUpdate() - { - debugString = ""; - if(hasFired && !hasExploded && part!=null) - { - part.rb.isKinematic = false; - AntiSpin(); - - //simpleDrag - if(useSimpleDrag) - { - SimpleDrag(); - } - - //flybyaudio - float mCamDistanceSqr = (FlightCamera.fetch.mainCamera.transform.position-transform.position).sqrMagnitude; - float mCamRelVSqr = (float)(FlightGlobals.ActiveVessel.srf_velocity-vessel.srf_velocity).sqrMagnitude; - if(!hasPlayedFlyby - && FlightGlobals.ActiveVessel != vessel - && FlightGlobals.ActiveVessel != sourceVessel - && mCamDistanceSqr < 400*400 && mCamRelVSqr > 300*300 - && mCamRelVSqr < 800*800 - && Vector3.Angle(vessel.srf_velocity, FlightGlobals.ActiveVessel.transform.position-transform.position)<60) - { - sfAudioSource.PlayOneShot (GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/missileFlyby")); - hasPlayedFlyby = true; - } - - if(vessel.isActiveVessel) - { - audioSource.dopplerLevel = 0; - } - else - { - audioSource.dopplerLevel = 1f; - } - - - //Missile State - timeIndex = Time.time - timeFired; - - if(timeIndex > 0.5f) - { - if(torpedo) - { - if(vessel.altitude > 0) - { - part.crashTolerance = waterImpactTolerance; - } - else - { - part.crashTolerance = 1; - } - } - else - { - part.crashTolerance = 1; - } - } - - - UpdateThrustForces(); - - UpdateGuidance(); - - RaycastCollisions(); - - //Timed detonation - if(isTimed && timeIndex > detonationTime) - { - part.temperature = part.maxTemp+100; - } - } - } - - Vector3 previousPos; - void RaycastCollisions() - { - if(weaponClass == WeaponClasses.Bomb) return; - - if(timeIndex > 1f && vessel.srfSpeed > part.crashTolerance) - { - /* - RaycastHit[] hits = Physics.RaycastAll(new Ray(previousPos, part.transform.position - previousPos), (part.transform.position - previousPos).magnitude, 557057); - for(int i = 0; i < hits.Length; i++) - { - if(hits[i].collider.gameObject.layer == 0 && hits[i].collider.attachedRigidbody && hits[i].collider.attachedRigidbody == part.rb) - { - continue; - } - else - { - Debug.Log(part.partInfo.title + " raycast detonated on " + (hits[i].collider.attachedRigidbody ? hits[i].collider.attachedRigidbody.gameObject.name : hits[i].collider.gameObject.name)); - part.temperature = part.maxTemp + 100; - } - } - */ - - RaycastHit lineHit; - if(Physics.Linecast(part.transform.position, previousPos, out lineHit, 557057)) - { - if(lineHit.collider.GetComponentInParent() != part) - { - Debug.Log(part.partInfo.title + " linecast hit on " + (lineHit.collider.attachedRigidbody ? lineHit.collider.attachedRigidbody.gameObject.name : lineHit.collider.gameObject.name)); - part.temperature = part.maxTemp + 100; - } - } - } - - previousPos = part.transform.position; - } - - void UpdateGuidance() - { - if(guidanceActive) - { - if(BDArmorySettings.ALLOW_LEGACY_TARGETING && legacyTargetVessel) - { - UpdateLegacyTarget(); - } - - if(targetingMode == TargetingModes.Heat) - { - UpdateHeatTarget(); - } - else if(targetingMode == TargetingModes.Radar) - { - UpdateRadarTarget(); - } - else if(targetingMode == TargetingModes.Laser) - { - UpdateLaserTarget(); - } - else if(targetingMode == TargetingModes.GPS) - { - UpdateGPSTarget(); - } - else if(targetingMode == TargetingModes.AntiRad) - { - UpdateAntiRadiationTarget(); - } - - } - - if(MissileState != MissileStates.Idle && MissileState != MissileStates.Drop) //guidance - { - //guidance and attitude stabilisation scales to atmospheric density. //use part.atmDensity - float atmosMultiplier = Mathf.Clamp01 (2.5f*(float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody)); - - if(vessel.srfSpeed < optimumAirspeed) - { - float optimumSpeedFactor = (float)vessel.srfSpeed / (2 * optimumAirspeed); - controlAuthority = Mathf.Clamp01(atmosMultiplier * (-Mathf.Abs(2 * optimumSpeedFactor - 1) + 1)); - } - else - { - controlAuthority = Mathf.Clamp01(atmosMultiplier); - } - debugString += "\ncontrolAuthority: "+controlAuthority; - - if(guidanceActive)// && timeIndex - dropTime > 0.5f) - { - WarnTarget(); - Vector3 targetPosition = Vector3.zero; - - if(legacyTargetVessel && legacyTargetVessel.loaded) - { - Vector3 targetCoMPos = legacyTargetVessel.findWorldCenterOfMass(); - targetPosition = targetCoMPos+legacyTargetVessel.rb_velocity*Time.fixedDeltaTime; - } - - //increaseTurnRate after launch - float turnRateDPS = Mathf.Clamp(((timeIndex-dropTime)/boostTime)*maxTurnRateDPS * 25f, 0, maxTurnRateDPS); - if(!hasRCS) - { - turnRateDPS *= controlAuthority; - } - - //decrease turn rate after thrust cuts out - if(timeIndex > dropTime+boostTime+cruiseTime) - { - turnRateDPS = atmosMultiplier * Mathf.Clamp(maxTurnRateDPS - ((timeIndex-dropTime-boostTime-cruiseTime)*0.45f), 1, maxTurnRateDPS); - if(hasRCS) - { - turnRateDPS = 0; - } - } - - if(hasRCS) - { - if(turnRateDPS > 0) - { - DoRCS(); - } - else - { - KillRCS(); - } - } - debugTurnRate = turnRateDPS; - - finalMaxTorque = Mathf.Clamp((timeIndex-dropTime)*torqueRampUp, 0, maxTorque); //ramp up torque - - if(guidanceMode == GuidanceModes.AAMLead) - { - AAMGuidance(); - } - else if(guidanceMode == GuidanceModes.AGM) - { - AGMGuidance(); - } - else if(guidanceMode == GuidanceModes.AGMBallistic) - { - AGMBallisticGuidance(); - } - else if(guidanceMode == GuidanceModes.BeamRiding) - { - BeamRideGuidance(); - } - else if(guidanceMode == GuidanceModes.RCS) - { - part.transform.rotation = Quaternion.RotateTowards(part.transform.rotation, Quaternion.LookRotation(targetPosition-part.transform.position, part.transform.up), turnRateDPS*Time.fixedDeltaTime); - } - else if(guidanceMode == GuidanceModes.Cruise) - { - CruiseGuidance(); - } - - - } - else - { - CheckMiss(); - targetMf = null; - if(aero) - { - aeroTorque = MissileGuidance.DoAeroForces(this, transform.position + (20*vessel.srf_velocity), liftArea, .25f, aeroTorque, maxTorque, maxAoA); - } - } - - if(aero && aeroSteerDamping > 0) - { - part.rb.AddRelativeTorque(-aeroSteerDamping * part.transform.InverseTransformVector(part.rb.angularVelocity)); - } - - if(hasRCS && !guidanceActive) - { - KillRCS(); - } - } - } - - void UpdateThrustForces() - { - if(currentThrust > 0) - { - part.rb.AddRelativeForce(currentThrust * Vector3.forward); - } - } - - IEnumerator MissileRoutine() - { - MissileState = MissileStates.Drop; - StartCoroutine(AnimRoutine()); - yield return new WaitForSeconds(dropTime); - yield return StartCoroutine(BoostRoutine()); - yield return new WaitForSeconds(cruiseDelay); - yield return StartCoroutine(CruiseRoutine()); - } - - IEnumerator AnimRoutine() - { - yield return new WaitForSeconds(deployTime); - - if(!string.IsNullOrEmpty(deployAnimationName)) - { - deployed = true; - - foreach(var anim in deployStates) - { - anim.speed = 1; - } - } - } - - IEnumerator BoostRoutine() - { - StartBoost(); - float boostStartTime = Time.time; - while(Time.time-boostStartTime < boostTime) - { - //light, sound & particle fx - //sound - if(!BDArmorySettings.GameIsPaused) - { - if(!audioSource.isPlaying) - { - audioSource.Play(); - } - } - else if(audioSource.isPlaying) - { - audioSource.Stop(); - } - - //particleFx - foreach(var emitter in boostEmitters) - { - if(!hasRCS) - { - emitter.sizeGrow = Mathf.Lerp(emitter.sizeGrow, 0, 20*Time.deltaTime); - } - } - foreach(var gpe in boostGaplessEmitters) - { - if(vessel.atmDensity > 0) - { - gpe.emit = true; - //gpe.pEmitter.worldVelocity = ParticleTurbulence.Turbulence; - gpe.pEmitter.worldVelocity = 2*ParticleTurbulence.flareTurbulence; - } - else - { - gpe.emit = false; - } - } - - //thrust - if(spoolEngine) - { - currentThrust = Mathf.MoveTowards(currentThrust, thrust, thrust/10); - } - - yield return null; - } - EndBoost(); - } - //boost - void StartBoost() - { - MissileState = MissileStates.Boost; - - if(boostAudio) - { - audioSource.clip = boostAudio; - } - else if(thrustAudio) - { - audioSource.clip = thrustAudio; - } - - foreach(Light light in gameObject.GetComponentsInChildren()) - { - light.intensity = 1.5f; - } - - - if(!spoolEngine) - { - currentThrust = thrust; - } - - if(string.IsNullOrEmpty(boostTransformName)) - { - boostEmitters = pEmitters; - boostGaplessEmitters = gaplessEmitters; - } - foreach(var emitter in boostEmitters) - { - emitter.emit = true; - } - - if(hasRCS) - { - forwardRCS.emit = true; - } - - if(thrust > 0) - { - sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/launch")); - RadarWarningReceiver.WarnMissileLaunch(transform.position, transform.forward); - } - - } - void EndBoost() - { - foreach(var emitter in boostEmitters) - { - if(!emitter) continue; - emitter.emit = false; - } - - foreach(var emitter in boostGaplessEmitters) - { - if(!emitter) continue; - emitter.emit = false; - } - - if(decoupleBoosters) - { - part.mass -= boosterMass; - foreach(var booster in boosters) - { - if(!booster) continue; - (booster.AddComponent()).DecoupleBooster(part.rb.velocity, boosterDecoupleSpeed); - } - } - - if(cruiseDelay > 0) - { - currentThrust = 0; - } - } - - IEnumerator CruiseRoutine() - { - StartCruise(); - float cruiseStartTime = Time.time; - while(Time.time - cruiseStartTime < cruiseTime) - { - if(!BDArmorySettings.GameIsPaused) - { - if(!audioSource.isPlaying || audioSource.clip != thrustAudio) - { - audioSource.clip = thrustAudio; - audioSource.Play(); - } - } - else if(audioSource.isPlaying) - { - audioSource.Stop(); - } - - //particleFx - foreach(var emitter in pEmitters) - { - if(!hasRCS) - { - emitter.sizeGrow = Mathf.Lerp(emitter.sizeGrow, 0, 20*Time.deltaTime); - } - } - foreach(var gpe in gaplessEmitters) - { - if(vessel.atmDensity > 0) - { - gpe.emit = true; - //gpe.pEmitter.worldVelocity = ParticleTurbulence.Turbulence; - gpe.pEmitter.worldVelocity = 2*ParticleTurbulence.flareTurbulence; - } - else - { - gpe.emit = false; - } - } - - if(spoolEngine) - { - currentThrust = Mathf.MoveTowards(currentThrust, cruiseThrust, cruiseThrust/10); - } - - - - yield return null; - } - EndCruise(); - } - - void StartCruise() - { - MissileState = MissileStates.Cruise; - - if(thrustAudio) - { - audioSource.clip = thrustAudio; - } - - if(spoolEngine) - { - currentThrust = 0; - } - else - { - currentThrust = cruiseThrust; - } - - foreach(var emitter in pEmitters) - { - emitter.emit = true; - } - - foreach(var emitter in gaplessEmitters) - { - emitter.emit = true; - } - - if(hasRCS) - { - forwardRCS.emit = false; - audioSource.Stop(); - } - } - - void EndCruise() - { - MissileState = MissileStates.PostThrust; - - foreach(Light light in gameObject.GetComponentsInChildren()) - { - light.intensity = 0; - } - - StartCoroutine(FadeOutAudio()); - StartCoroutine(FadeOutEmitters()); - } - - IEnumerator FadeOutAudio() - { - if(thrustAudio && audioSource.isPlaying) - { - while(audioSource.volume > 0 || audioSource.pitch > 0) - { - audioSource.volume = Mathf.Lerp(audioSource.volume, 0, 5*Time.deltaTime); - audioSource.pitch = Mathf.Lerp(audioSource.pitch, 0, 5*Time.deltaTime); - yield return null; - } - } - } - - IEnumerator FadeOutEmitters() - { - float fadeoutStartTime = Time.time; - while(Time.time-fadeoutStartTime < 5) - { - foreach(KSPParticleEmitter pe in pEmitters) - { - if(!pe) continue; - pe.maxEmission = Mathf.FloorToInt(pe.maxEmission * 0.8f); - pe.minEmission = Mathf.FloorToInt(pe.minEmission * 0.8f); - } - - foreach(var gpe in gaplessEmitters) - { - if(!gpe) continue; - gpe.pEmitter.maxSize = Mathf.MoveTowards(gpe.pEmitter.maxSize, 0, 0.005f); - gpe.pEmitter.minSize = Mathf.MoveTowards(gpe.pEmitter.minSize, 0, 0.008f); - gpe.pEmitter.worldVelocity = ParticleTurbulence.Turbulence; - } - - yield return new WaitForFixedUpdate(); - } - - foreach(KSPParticleEmitter pe in pEmitters) - { - if(!pe) continue; - pe.emit = false; - } - - foreach(var gpe in gaplessEmitters) - { - if(!gpe) continue; - gpe.emit = false; - } - } - - [KSPField] - public float beamCorrectionFactor; - [KSPField] - public float beamCorrectionDamping; - - ModuleTargetingCamera targetingPod; - Ray previousBeam; - void BeamRideGuidance() - { - if(!targetingPod) - { - guidanceActive = false; - return; - } - - if(RadarUtils.TerrainCheck(targetingPod.cameraParentTransform.position, transform.position)) - { - guidanceActive = false; - return; - } - Ray laserBeam = new Ray(targetingPod.cameraParentTransform.position + (targetingPod.vessel.rb_velocity * Time.fixedDeltaTime), targetingPod.targetPointPosition - targetingPod.cameraParentTransform.position); - Vector3 target = MissileGuidance.GetBeamRideTarget(laserBeam, part.transform.position, vessel.srf_velocity, beamCorrectionFactor, beamCorrectionDamping, (timeIndex > 0.25f ? previousBeam : laserBeam)); - previousBeam = laserBeam; - DrawDebugLine(part.transform.position, target); - DoAero(target); - } - - void CruiseGuidance() - { - Vector3 cruiseTarget = Vector3.zero; - float distance = Vector3.Distance(targetPosition, transform.position); - - if(terminalManeuvering && distance < 4500) - { - cruiseTarget = MissileGuidance.GetTerminalManeuveringTarget(targetPosition, vessel, cruiseAltitude); - debugString += "\nTerminal Maneuvers"; - } - else - { - float agmThreshDist = 2500; - if(distance maxOffBoresight*0.75f) - { - aamTarget = targetPosition; - } - - //proxy detonation - if(proxyDetonate && ((targetPosition+(targetVelocity*Time.fixedDeltaTime))-(transform.position)).sqrMagnitude < Mathf.Pow(blastRadius*0.5f,2)) - { - part.temperature = part.maxTemp + 100; - } - } - else - { - aamTarget = transform.position + (20*vessel.srf_velocity.normalized); - } - - - if(Time.time-timeFired > dropTime+0.25f) - { - DoAero(aamTarget); - } - - CheckMiss(); - } - - void AGMGuidance() - { - if(targetingMode != TargetingModes.GPS) - { - if(targetAcquired) - { - //lose lock if seeker reaches gimbal limit - float targetViewAngle = Vector3.Angle(transform.forward, targetPosition - transform.position); - - if(targetViewAngle > maxOffBoresight) - { - Debug.Log("AGM Missile guidance failed - target out of view"); - guidanceActive = false; - } - CheckMiss(); - } - else - { - if(targetingMode == TargetingModes.Laser) - { - //keep going straight until found laser point - targetPosition = laserStartPosition + (20000 * startDirection); - } - } - } - - Vector3 agmTarget = MissileGuidance.GetAirToGroundTarget(targetPosition, vessel, agmDescentRatio); - - DoAero(agmTarget); - } - - void DoAero(Vector3 targetPosition) - { - aeroTorque = MissileGuidance.DoAeroForces(this, targetPosition, liftArea, controlAuthority * steerMult, aeroTorque, finalMaxTorque, maxAoA); - } - - void AGMBallisticGuidance() - { - Vector3 agmTarget; - bool validSolution = MissileGuidance.GetBallisticGuidanceTarget(targetPosition, vessel, !indirect, out agmTarget); - if(!validSolution || Vector3.Angle(targetPosition - transform.position, agmTarget - transform.position) > Mathf.Clamp(maxOffBoresight, 0, 65)) - { - Vector3 dToTarget = targetPosition - transform.position; - Vector3 direction = Quaternion.AngleAxis(Mathf.Clamp(maxOffBoresight * 0.9f, 0, 45f), Vector3.Cross(dToTarget, VectorUtils.GetUpDirection(transform.position))) * dToTarget; - agmTarget = transform.position + direction; - } - - DoAero(agmTarget); - } - - void UpdateGPSTarget() - { - if(targetAcquired) - { - targetPosition = VectorUtils.GetWorldSurfacePostion(targetGPSCoords, vessel.mainBody); - targetVelocity = Vector3.zero; - targetAcceleration = Vector3.zero; - } - else - { - guidanceActive = false; - } - } - - void UpdateLaserTarget() - { - if(targetAcquired) - { - if(lockedCamera && lockedCamera.groundStabilized && !lockedCamera.gimbalLimitReached && lockedCamera.surfaceDetected) //active laser target - { - targetPosition = lockedCamera.groundTargetPosition; - targetVelocity = (targetPosition - lastLaserPoint) / Time.fixedDeltaTime; - targetAcceleration = Vector3.zero; - lastLaserPoint = targetPosition; - - if(guidanceMode == GuidanceModes.BeamRiding && timeIndex > 0.25f && Vector3.Dot(part.transform.forward, part.transform.position - lockedCamera.transform.position) < 0) - { - targetAcquired = false; - lockedCamera = null; - } - } - else //lost active laser target, home on last known position - { - if(CMSmoke.RaycastSmoke(new Ray(transform.position, lastLaserPoint - transform.position))) - { - //Debug.Log("Laser missile affected by smoke countermeasure"); - float angle = VectorUtils.FullRangePerlinNoise(0.75f * Time.time, 10) * BDArmorySettings.SMOKE_DEFLECTION_FACTOR; - targetPosition = VectorUtils.RotatePointAround(lastLaserPoint, transform.position, VectorUtils.GetUpDirection(transform.position), angle); - targetVelocity = Vector3.zero; - targetAcceleration = Vector3.zero; - lastLaserPoint = targetPosition; - } - else - { - targetPosition = lastLaserPoint; - } - } - } - else - { - ModuleTargetingCamera foundCam = null; - bool parentOnly = (guidanceMode == GuidanceModes.BeamRiding); - foundCam = BDATargetManager.GetLaserTarget(this, parentOnly); - if(foundCam != null && foundCam.cameraEnabled && foundCam.groundStabilized && CanSeePosition(foundCam.groundTargetPosition)) - { - Debug.Log("Laser guided missile actively found laser point. Enabling guidance."); - lockedCamera = foundCam; - targetAcquired = true; - } - } - } - - void UpdateLegacyTarget() - { - if(legacyTargetVessel) - { - maxOffBoresight = 90; - - if(targetingMode == TargetingModes.Radar) - { - activeRadarRange = 20000; - targetAcquired = true; - radarTarget = new TargetSignatureData(legacyTargetVessel, 500); - return; - } - else if(targetingMode == TargetingModes.Heat) - { - targetAcquired = true; - heatTarget = new TargetSignatureData(legacyTargetVessel, 500); - return; - } - - if(targetingMode != TargetingModes.GPS || targetAcquired) - { - targetAcquired = true; - targetPosition = legacyTargetVessel.CoM + (legacyTargetVessel.rb_velocity * Time.fixedDeltaTime); - targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(targetPosition, vessel.mainBody); - targetVelocity = legacyTargetVessel.srf_velocity; - targetAcceleration = legacyTargetVessel.acceleration; - lastLaserPoint = targetPosition; - lockFailTimer = 0; - } - } - } - - void UpdateAntiRadiationTarget() - { - if(!targetAcquired) - { - guidanceActive = false; - return; - } - - if(FlightGlobals.ready) - { - if(lockFailTimer < 0) - { - lockFailTimer = 0; - } - lockFailTimer += Time.fixedDeltaTime; - } - - if(lockFailTimer > 8) - { - guidanceActive = false; - targetAcquired = false; - } - else - { - targetPosition = VectorUtils.GetWorldSurfacePostion(targetGPSCoords, vessel.mainBody); - } - } - - void ReceiveRadarPing(Vessel v, Vector3 source, RadarWarningReceiver.RWRThreatTypes type, float persistTime) - { - if(targetingMode == TargetingModes.AntiRad && targetAcquired && v == vessel) - { - if((source - VectorUtils.GetWorldSurfacePostion(targetGPSCoords, vessel.mainBody)).sqrMagnitude < Mathf.Pow(50, 2) - && Vector3.Angle(source-transform.position, transform.forward) < maxOffBoresight) - { - targetAcquired = true; - targetPosition = source; - targetGPSCoords = VectorUtils.WorldPositionToGeoCoords(targetPosition, vessel.mainBody); - targetVelocity = Vector3.zero; - targetAcceleration = Vector3.zero; - lockFailTimer = 0; - } - } - } - - int snapshotTicker; - int locksCount = 0; - TargetSignatureData[] scannedTargets; - float radarFailTimer = 0; - float maxRadarFailTime = 1; - void UpdateRadarTarget() - { - targetAcquired = false; - - float angleToTarget = Vector3.Angle(radarTarget.predictedPosition-transform.position,transform.forward); - if(radarTarget.exists) - { - if(!activeRadar && ((radarTarget.predictedPosition - transform.position).sqrMagnitude > Mathf.Pow(activeRadarRange, 2) || angleToTarget > maxOffBoresight * 0.75f)) - { - if(vrd) - { - TargetSignatureData t = TargetSignatureData.noTarget; - List possibleTargets = vrd.GetLockedTargets(); - for(int i = 0; i < possibleTargets.Count; i++) - { - if(possibleTargets[i].vessel == radarTarget.vessel) - { - t = possibleTargets[i]; - } - } - - - if(t.exists) - { - targetAcquired = true; - radarTarget = t; - targetPosition = radarTarget.predictedPosition; - targetVelocity = radarTarget.velocity; - targetAcceleration = radarTarget.acceleration; - radarFailTimer = 0; - return; - } - else - { - if(radarFailTimer > maxRadarFailTime) - { - Debug.Log("Semi-Active Radar guidance failed. Parent radar lost target."); - radarTarget = TargetSignatureData.noTarget; - legacyTargetVessel = null; - return; - } - else - { - if(radarFailTimer == 0) - { - Debug.Log("Semi-Active Radar guidance failed - waiting for data"); - } - radarFailTimer += Time.fixedDeltaTime; - radarTarget.timeAcquired = Time.time; - radarTarget.position = radarTarget.predictedPosition; - targetPosition = radarTarget.predictedPosition; - targetVelocity = radarTarget.velocity; - targetAcceleration = Vector3.zero; - targetAcquired = true; - } - } - } - else - { - Debug.Log("Semi-Active Radar guidance failed. Out of range and no data feed."); - radarTarget = TargetSignatureData.noTarget; - legacyTargetVessel = null; - return; - } - } - else - { - vrd = null; - - if(angleToTarget > maxOffBoresight) - { - Debug.Log("Radar guidance failed. Target is out of active seeker gimbal limits."); - radarTarget = TargetSignatureData.noTarget; - legacyTargetVessel = null; - return; - } - else - { - if(scannedTargets == null) scannedTargets = new TargetSignatureData[5]; - TargetSignatureData.ResetTSDArray(ref scannedTargets); - Ray ray = new Ray(transform.position, radarTarget.predictedPosition - transform.position); - bool pingRWR = Time.time - lastRWRPing > 0.4f; - if(pingRWR) lastRWRPing = Time.time; - bool radarSnapshot = (snapshotTicker > 20); - if(radarSnapshot) - { - snapshotTicker = 0; - } - else - { - snapshotTicker++; - } - RadarUtils.UpdateRadarLock(ray, lockedSensorFOV, activeRadarMinThresh, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); - float sqrThresh = radarLOALSearching ? Mathf.Pow(500, 2) : Mathf.Pow(40, 2); - - if(radarLOAL && radarLOALSearching && !radarSnapshot) - { - //only scan on snapshot interval - } - else - { - for(int i = 0; i < scannedTargets.Length; i++) - { - if(scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) - { - radarTarget = scannedTargets[i]; - targetAcquired = true; - radarLOALSearching = false; - targetPosition = radarTarget.predictedPosition + (radarTarget.velocity * Time.fixedDeltaTime); - targetVelocity = radarTarget.velocity; - targetAcceleration = radarTarget.acceleration; - radarFailTimer = 0; - if(!activeRadar && Time.time - timeFired > 1) - { - if(locksCount == 0) - { - RadarWarningReceiver.PingRWR(ray, lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); - Debug.Log("Pitbull! Radar missile has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); - - } - else if(locksCount > 2) - { - guidanceActive = false; - checkMiss = true; - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - Debug.Log("Radar missile reached max re-lock attempts."); - } - } - locksCount++; - } - activeRadar = true; - return; - } - } - } - - if(radarLOAL) - { - radarLOALSearching = true; - targetAcquired = true; - targetPosition = radarTarget.predictedPosition + (radarTarget.velocity * Time.fixedDeltaTime); - targetVelocity = radarTarget.velocity; - targetAcceleration = Vector3.zero; - activeRadar = false; - } - else - { - radarTarget = TargetSignatureData.noTarget; - } - - } - } - } - else if(radarLOAL && radarLOALSearching) - { - if(scannedTargets == null) scannedTargets = new TargetSignatureData[5]; - TargetSignatureData.ResetTSDArray(ref scannedTargets); - Ray ray = new Ray(transform.position, transform.forward); - bool pingRWR = Time.time - lastRWRPing > 0.4f; - if(pingRWR) lastRWRPing = Time.time; - bool radarSnapshot = (snapshotTicker > 6); - if(radarSnapshot) - { - snapshotTicker = 0; - } - else - { - snapshotTicker++; - } - RadarUtils.UpdateRadarLock(ray, lockedSensorFOV*3, activeRadarMinThresh*2, ref scannedTargets, 0.4f, pingRWR, RadarWarningReceiver.RWRThreatTypes.MissileLock, radarSnapshot); - float sqrThresh = Mathf.Pow(300, 2); - - float smallestAngle = 360; - TargetSignatureData lockedTarget = TargetSignatureData.noTarget; - - for(int i = 0; i < scannedTargets.Length; i++) - { - if(scannedTargets[i].exists && (scannedTargets[i].predictedPosition - radarTarget.predictedPosition).sqrMagnitude < sqrThresh) - { - float angle = Vector3.Angle(scannedTargets[i].predictedPosition - transform.position, transform.forward); - if(angle < smallestAngle) - { - lockedTarget = scannedTargets[i]; - smallestAngle = angle; - } - - - activeRadar = true; - return; - } - } - - if(lockedTarget.exists) - { - radarTarget = lockedTarget; - targetAcquired = true; - radarLOALSearching = false; - targetPosition = radarTarget.predictedPosition + (radarTarget.velocity * Time.fixedDeltaTime); - targetVelocity = radarTarget.velocity; - targetAcceleration = radarTarget.acceleration; - - if(!activeRadar && Time.time - timeFired > 1) - { - RadarWarningReceiver.PingRWR(new Ray(transform.position, radarTarget.predictedPosition - transform.position), lockedSensorFOV, RadarWarningReceiver.RWRThreatTypes.MissileLaunch, 2f); - Debug.Log("Pitbull! Radar missile has gone active. Radar sig strength: " + radarTarget.signalStrength.ToString("0.0")); - } - return; - } - else - { - targetAcquired = true; - targetPosition = transform.position + (startDirection * 500); - targetVelocity = Vector3.zero; - targetAcceleration = Vector3.zero; - radarLOALSearching = true; - return; - } - } - - if(!radarTarget.exists) - { - legacyTargetVessel = null; - } - } - - void UpdateHeatTarget() - { - targetAcquired = false; - - if(lockFailTimer > 1) - { - legacyTargetVessel = null; - - return; - } - - if(heatTarget.exists && lockFailTimer < 0) - { - lockFailTimer = 0; - } - if(lockFailTimer >= 0) - { - Ray lookRay = new Ray(transform.position, heatTarget.position+(heatTarget.velocity*Time.fixedDeltaTime)-transform.position); - heatTarget = BDATargetManager.GetHeatTarget(lookRay, lockedSensorFOV/2, heatThreshold, allAspect); - - if(heatTarget.exists) - { - targetAcquired = true; - targetPosition = heatTarget.position+(2*heatTarget.velocity*Time.fixedDeltaTime); - targetVelocity = heatTarget.velocity; - targetAcceleration = heatTarget.acceleration; - lockFailTimer = 0; - } - else - { - if(FlightGlobals.ready) - { - lockFailTimer += Time.fixedDeltaTime; - } - } - } - - - } - - void CheckMiss() - { - float sqrDist = ((targetPosition+(targetVelocity*Time.fixedDeltaTime))-(transform.position+(part.rb.velocity*Time.fixedDeltaTime))).sqrMagnitude; - if(sqrDist < 160000 || (MissileState == MissileStates.PostThrust && (guidanceMode == GuidanceModes.AAMLead || guidanceMode == GuidanceModes.AAMPure))) - { - checkMiss = true; - } - - //kill guidance if missile has missed - if(!hasMissed && checkMiss) - { - bool noProgress = MissileState == MissileStates.PostThrust && (Vector3.Dot(vessel.srf_velocity-targetVelocity, targetPosition - vessel.transform.position) < 0); - if(Vector3.Dot(targetPosition-transform.position,transform.forward) < 0 || noProgress) - { - Debug.Log ("Missile CheckMiss showed miss"); - hasMissed = true; - guidanceActive = false; - targetMf = null; - if(hasRCS) KillRCS(); - if(sqrDist < Mathf.Pow(blastRadius * 0.5f, 2)) part.temperature = part.maxTemp + 100; - - isTimed = true; - detonationTime = Time.time - timeFired + 1.5f; - return; - } - } - } - - void RayDetonator() - { - Vector3 lineStart = transform.position; - Vector3 lineEnd = transform.position + part.rb.velocity; - RaycastHit rayHit; - if(Physics.Linecast(lineStart, lineEnd, out rayHit, 557057)) - { - if(rayHit.collider.attachedRigidbody && rayHit.collider.attachedRigidbody != part.rb) - { - part.temperature = part.temperature + 100; - } - } - - } - - - - void DrawDebugLine(Vector3 start, Vector3 end) - { - if(BDArmorySettings.DRAW_DEBUG_LINES) - { - if(!gameObject.GetComponent()) - { - LR = gameObject.AddComponent(); - LR.material = new Material(Shader.Find("KSP/Emissive/Diffuse")); - LR.material.SetColor("_EmissiveColor", Color.red); - }else - { - LR = gameObject.GetComponent(); - } - LR.SetVertexCount(2); - LR.SetPosition(0, start); - LR.SetPosition(1, end); - } - } - - - - public void Detonate() - { - if(isSeismicCharge) - { - DetonateSeismicCharge(); - - } - else if(!hasExploded && hasFired) - { - BDArmorySettings.numberOfParticleEmitters--; - - hasExploded = true; - - - if(legacyTargetVessel!=null) - { - foreach(var wpm in legacyTargetVessel.FindPartModulesImplementing()) - { - wpm.missileIsIncoming = false; - } - } - - if(part!=null) part.temperature = part.maxTemp + 100; - Vector3 position = transform.position;//+rigidbody.velocity*Time.fixedDeltaTime; - if(sourceVessel==null) sourceVessel = vessel; - ExplosionFX.CreateExplosion(position, blastRadius, blastPower, blastHeat, sourceVessel, transform.forward, explModelPath, explSoundPath); //TODO: apply separate heat damage - - foreach(var e in gaplessEmitters) - { - e.gameObject.AddComponent(); - e.transform.parent = null; - if(e.GetComponent()) - { - e.GetComponent().enabled = false; - } - } - } - } - - - void PartDie(Part p) - { - if(p == part) - { - Detonate(); - BDATargetManager.FiredMissiles.Remove(this); - GameEvents.onPartDie.Remove(PartDie); - } - } - - - - public bool CanSeePosition(Vector3 pos) - { - if((pos-transform.position).sqrMagnitude < Mathf.Pow(20,2)) - { - return false; - } - - float dist = 10000; - Ray ray = new Ray(missileReferenceTransform.position, pos-missileReferenceTransform.position); - ray.origin += 10 * ray.direction; - RaycastHit rayHit; - if(Physics.Raycast(ray, out rayHit, dist, 557057)) - { - if((rayHit.point-pos).sqrMagnitude < 200) - { - return true; - } - else - { - return false; - } - } - - return true; - } - - - - - void DetonateSeismicCharge() - { - if(!hasExploded && hasFired) - { - GameSettings.SHIP_VOLUME = 0; - GameSettings.MUSIC_VOLUME = 0; - GameSettings.AMBIENCE_VOLUME = 0; - - BDArmorySettings.numberOfParticleEmitters--; - - hasExploded = true; - - /* - if(targetVessel == null) - { - if(target!=null && FlightGlobals.ActiveVessel.gameObject == target) - { - targetVessel = FlightGlobals.ActiveVessel; - } - else if(target!=null && !BDArmorySettings.Flares.Contains(t => t.gameObject == target)) - { - targetVessel = Part.FromGO(target).vessel; - } - - } - */ - if(legacyTargetVessel!=null) - { - foreach(var wpm in legacyTargetVessel.FindPartModulesImplementing()) - { - wpm.missileIsIncoming = false; - } - } - - if(part!=null) - { - - part.temperature = part.maxTemp + 100; - } - Vector3 position = transform.position+part.rb.velocity*Time.fixedDeltaTime; - if(sourceVessel==null) sourceVessel = vessel; - - SeismicChargeFX.CreateSeismicExplosion(transform.position-(part.rb.velocity.normalized*15), UnityEngine.Random.rotation); - - } - } - - - - public static bool CheckIfMissile(Part p) - { - if(p.GetComponent()) - { - return true; - } - else return false; - } - - - - void WarnTarget() - { - if(legacyTargetVessel == null) - { - return; - /* - if(FlightGlobals.ActiveVessel.gameObject == target) - { - targetVessel = FlightGlobals.ActiveVessel; - } - else if(target!=null && !BDArmorySettings.Flares.Contains(target)) - { - targetVessel = Part.FromGO(target).vessel; - } - */ - - } - - if(legacyTargetVessel!=null) - { - foreach(var wpm in legacyTargetVessel.FindPartModulesImplementing()) - { - wpm.MissileWarning(Vector3.Distance(transform.position, legacyTargetVessel.transform.position), this); - break; - } - } - } - - - float[] rcsFiredTimes; - KSPParticleEmitter[] rcsTransforms; - void SetupRCS() - { - rcsFiredTimes = new float[]{0,0,0,0}; - rcsTransforms = new KSPParticleEmitter[]{upRCS, leftRCS, rightRCS, downRCS}; - } - - - - void DoRCS() - { - Vector3 relV = targetVelocity-vessel.obt_velocity; - - for(int i = 0; i < 4; i++) - { - //Vector3 relV = legacyTargetVessel.obt_velocity-vessel.obt_velocity; - - //Vector3 relV = vessel.obt_velocity-targetVelocity; - //Vector3 localRelV = rcsTransforms[i].transform.InverseTransformVector(relV); - - - //float giveThrust = Mathf.Clamp(-localRelV.z, 0, rcsThrust); - float giveThrust = Mathf.Clamp(Vector3.Project(relV, rcsTransforms[i].transform.forward).magnitude * -Mathf.Sign(Vector3.Dot(rcsTransforms[i].transform.forward, relV)), 0, rcsThrust); - part.rb.AddForce(-giveThrust*rcsTransforms[i].transform.forward); - - if(giveThrust > rcsRVelThreshold) - { - rcsAudioMinInterval = UnityEngine.Random.Range(0.15f,0.25f); - if(Time.time-rcsFiredTimes[i] > rcsAudioMinInterval) - { - sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/popThrust")); - rcsTransforms[i].emit = true; - rcsFiredTimes[i] = Time.time; - } - } - else - { - rcsTransforms[i].emit = false; - } - - //turn off emit - if(Time.time-rcsFiredTimes[i] > rcsAudioMinInterval*0.75f) - { - rcsTransforms[i].emit = false; - } - } - - - } - - void KillRCS() - { - upRCS.emit = false; - downRCS.emit = false; - leftRCS.emit = false; - rightRCS.emit = false; - } - - - void OnGUI() - { - if(hasFired && BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(200,200,200,200), debugString); - - - } - if(hasFired && hasRCS) - { - BDGUIUtils.DrawLineBetweenWorldPositions(transform.position, targetPosition, 2, Color.red); - } - } - - - void AntiSpin() - { - part.rb.angularDrag = 0; - part.angularDrag = 0; - Vector3 spin = Vector3.Project(part.rb.angularVelocity, part.rb.transform.forward);// * 8 * Time.fixedDeltaTime; - part.rb.angularVelocity -= spin; - //rigidbody.maxAngularVelocity = 7; - - if(guidanceActive) - { - part.rb.angularVelocity -= 0.6f * part.rb.angularVelocity; - } - else - { - part.rb.angularVelocity -= 0.02f * part.rb.angularVelocity; - } - } - - void SimpleDrag() - { - part.dragModel = Part.DragModel.NONE; - //float simSpeedSquared = (float)vessel.srf_velocity.sqrMagnitude; - float simSpeedSquared = (part.rb.GetPointVelocity(part.transform.TransformPoint(simpleCoD))+(Vector3)Krakensbane.GetFrameVelocity()).sqrMagnitude; - Vector3 currPos = transform.position; - float drag = deployed ? deployedDrag : simpleDrag; - float dragMagnitude = (0.008f * part.rb.mass) * drag * 0.5f * simSpeedSquared * (float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPos), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody); - Vector3 dragForce = dragMagnitude * vessel.srf_velocity.normalized; - part.rb.AddForceAtPosition(-dragForce, transform.TransformPoint(simpleCoD)); - - Vector3 torqueAxis = -Vector3.Cross(vessel.srf_velocity, part.transform.forward).normalized; - float AoA = Vector3.Angle(part.transform.forward, vessel.srf_velocity); - AoA /= 20; - part.rb.AddTorque(AoA * simpleStableTorque * dragMagnitude * torqueAxis); - } - - void ParseModes() - { - homingType = homingType.ToLower(); - switch(homingType) - { - case "aam": - guidanceMode = GuidanceModes.AAMLead; - break; - case "aamlead": - guidanceMode = GuidanceModes.AAMLead; - break; - case "aampure": - guidanceMode = GuidanceModes.AAMPure; - break; - case "agm": - guidanceMode = GuidanceModes.AGM; - break; - case "agmballistic": - guidanceMode = GuidanceModes.AGMBallistic; - break; - case "cruise": - guidanceMode = GuidanceModes.Cruise; - break; - case "sts": - guidanceMode = GuidanceModes.STS; - break; - case "rcs": - guidanceMode = GuidanceModes.RCS; - break; - case "beamriding": - guidanceMode = GuidanceModes.BeamRiding; - break; - default: - guidanceMode = GuidanceModes.None; - break; - } - - targetingType = targetingType.ToLower(); - switch(targetingType) - { - case "radar": - targetingMode = TargetingModes.Radar; - break; - case "heat": - targetingMode = TargetingModes.Heat; - break; - case "laser": - targetingMode = TargetingModes.Laser; - break; - case "gps": - targetingMode = TargetingModes.GPS; - maxOffBoresight = 360; - break; - case "antirad": - targetingMode = TargetingModes.AntiRad; - break; - default: - targetingMode = TargetingModes.None; - break; - } - - tModeString = Enum.GetName(typeof(TargetingModes), targetingMode); - } - - } -} - diff --git a/BahaTurret/MissileTurret.cs b/BahaTurret/MissileTurret.cs deleted file mode 100644 index 64d5c1863..000000000 --- a/BahaTurret/MissileTurret.cs +++ /dev/null @@ -1,647 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class MissileTurret : PartModule - { - [KSPField] - public string finalTransformName; - public Transform finalTransform; - - [KSPField] - public int turretID = 0; - - ModuleTurret turret; - - [KSPField(guiActive = true, guiName = "Turret Enabled")] - public bool turretEnabled = false; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Auto-Return"), UI_Toggle(scene = UI_Scene.Editor)] - public bool autoReturn = true; - bool hasReturned = true; - - [KSPField] - public float railLength = 3; - - Coroutine returnRoutine; - - int missileCount = 0; - MissileLauncher[] missileChildren; - Transform[] missileTransforms; - Transform[] missileReferenceTransforms; - - Dictionary comOffsets; - - public bool slaved = false; - - public Vector3 slavedTargetPosition; - - bool pausingAfterShot = false; - float timeFired = 0; - [KSPField] - public float firePauseTime = 0.25f; - - ModuleRadar attachedRadar; - bool hasAttachedRadar = false; - [KSPField] - public bool disableRadarYaw = false; - [KSPField] - public bool disableRadarPitch = false; - - [KSPField] - public bool mouseControllable = true; - - //animation - [KSPField] - public string deployAnimationName; - AnimationState deployAnimState; - bool hasDeployAnimation = false; - [KSPField] - public float deployAnimationSpeed = 1; - bool editorDeployed = false; - Coroutine deployAnimRoutine; - - //special - [KSPField] - public bool activeMissileOnly = false; - - MissileFire wm; - public MissileFire weaponManager - { - get - { - if(!wm || wm.vessel != vessel) - { - wm = null; - - foreach(var mf in vessel.FindPartModulesImplementing()) - { - wm = mf; - break; - } - } - - return wm; - } - } - - IEnumerator DeployAnimation(bool forward) - { - yield return null; - - if(forward) - { - while(deployAnimState.normalizedTime < 1) - { - deployAnimState.speed = deployAnimationSpeed; - yield return null; - } - - deployAnimState.normalizedTime = 1; - } - else - { - deployAnimState.speed = 0; - - while(pausingAfterShot) - { - yield return new WaitForFixedUpdate(); - } - - while(deployAnimState.normalizedTime > 0) - { - deployAnimState.speed = -deployAnimationSpeed; - yield return null; - } - - deployAnimState.normalizedTime = 0; - } - - deployAnimState.speed = 0; - } - - public void EnableTurret() - { - if(!HighLogic.LoadedSceneIsFlight) - { - return; - } - - if(returnRoutine!=null) - { - StopCoroutine(returnRoutine); - returnRoutine = null; - } - - turretEnabled = true; - hasReturned = false; - - if(hasAttachedRadar) - { - attachedRadar.lockingYaw = !disableRadarYaw; - attachedRadar.lockingPitch = !disableRadarPitch; - } - - if(!autoReturn) - { - Events["ReturnTurret"].guiActive = false; - } - - if(hasDeployAnimation) - { - if(deployAnimRoutine != null) - { - StopCoroutine(deployAnimRoutine); - } - - deployAnimRoutine = StartCoroutine(DeployAnimation(true)); - } - } - - - public void DisableTurret() - { - turretEnabled = false; - - if(autoReturn) - { - hasReturned = true; - if(returnRoutine != null) - { - StopCoroutine(returnRoutine); - } - returnRoutine = StartCoroutine(ReturnRoutine()); - } - - if(hasAttachedRadar) - { - attachedRadar.lockingYaw = true; - attachedRadar.lockingPitch = true; - } - - if(!autoReturn) - { - Events["ReturnTurret"].guiActive = true; - } - - if(hasDeployAnimation) - { - if(deployAnimRoutine != null) - { - StopCoroutine(deployAnimRoutine); - } - - deployAnimRoutine = StartCoroutine(DeployAnimation(false)); - } - } - - [KSPEvent(guiActive = false, guiActiveEditor = false, guiName = "Return Turret")] - public void ReturnTurret() - { - if(!turretEnabled) - { - returnRoutine = StartCoroutine(ReturnRoutine()); - hasReturned = true; - } - } - - [KSPEvent(guiActive = false, guiActiveEditor = false, guiName = "Toggle Animation")] - public void EditorToggleAnimation() - { - editorDeployed = !editorDeployed; - - if(deployAnimRoutine != null) - { - StopCoroutine(deployAnimRoutine); - } - - deployAnimRoutine = StartCoroutine(DeployAnimation(editorDeployed)); - } - - IEnumerator ReturnRoutine() - { - if(turretEnabled) - { - hasReturned = false; - yield break; - } - - yield return new WaitForSeconds(0.25f); - - while(pausingAfterShot) - { - yield return new WaitForFixedUpdate(); - } - - while(!turret.ReturnTurret()) - { - UpdateMissilePositions(); - yield return new WaitForFixedUpdate(); - } - } - - public override void OnStart(StartState state) - { - base.OnStart(state); - - part.force_activate(); - - //setup anim - if(!string.IsNullOrEmpty(deployAnimationName)) - { - hasDeployAnimation = true; - deployAnimState = Misc.SetUpSingleAnimation(deployAnimationName, part); - if(state == StartState.Editor) - { - Events["EditorToggleAnimation"].guiActiveEditor = true; - } - } - - if(HighLogic.LoadedSceneIsFlight) - { - foreach(var tur in part.FindModulesImplementing()) - { - if(tur.turretID == turretID) - { - turret = tur; - break; - } - } - - attachedRadar = part.FindModuleImplementing(); - if(attachedRadar) hasAttachedRadar = true; - - finalTransform = part.FindModelTransform(finalTransformName); - - UpdateMissileChildren(); - - if(!autoReturn) - { - Events["ReturnTurret"].guiActive = true; - } - } - } - - public override void OnFixedUpdate() - { - base.OnFixedUpdate(); - - - - if(turretEnabled) - { - hasReturned = false; - - if(missileCount == 0) - { - DisableTurret(); - return; - } - - Aim(); - UpdateMissilePositions(); - - if(!vessel.IsControllable) - { - DisableTurret(); - } - - } - else - { - if(Quaternion.FromToRotation(finalTransform.forward, turret.yawTransform.parent.parent.forward) != Quaternion.identity) - { - UpdateMissilePositions(); - } - - if(autoReturn && !hasReturned) - { - DisableTurret(); - } - - - - } - - pausingAfterShot = (Time.time - timeFired < firePauseTime); - } - - - void Aim() - { - UpdateTarget(); - - if(slaved) - { - SlavedAim(); - } - else - { - if(weaponManager && wm.guardMode) - { - return; - } - - if(mouseControllable && vessel.isActiveVessel) - { - MouseAim(); - } - } - } - - void UpdateTarget() - { - slaved = false; - - if(weaponManager && wm.slavingTurrets && wm.currentMissile) - { - slaved = true; - slavedTargetPosition = MissileGuidance.GetAirToAirFireSolution(wm.currentMissile, wm.slavedPosition, wm.slavedVelocity); - } - } - - - - public void SlavedAim() - { - if(pausingAfterShot) return; - - turret.AimToTarget(slavedTargetPosition); - } - - - void MouseAim() - { - if(pausingAfterShot) return; - - Vector3 targetPosition; - float maxTargetingRange = 5000; - - //MouseControl - Vector3 mouseAim = new Vector3(Input.mousePosition.x/Screen.width, Input.mousePosition.y/Screen.height, 0); - Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mouseAim); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, maxTargetingRange, 557057)) - { - targetPosition = hit.point; - - //aim through self vessel if occluding mouseray - Part p = hit.collider.gameObject.GetComponentInParent(); - if(p && p.vessel && p.vessel == vessel) - { - targetPosition = ray.direction * maxTargetingRange + FlightCamera.fetch.mainCamera.transform.position; - } - } - else - { - targetPosition = (ray.direction * (maxTargetingRange+(FlightCamera.fetch.Distance*0.75f))) + FlightCamera.fetch.mainCamera.transform.position; - } - - turret.AimToTarget(targetPosition); - } - - public void UpdateMissileChildren() - { - missileCount = 0; - - //setup com dictionary - if(comOffsets == null) - { - comOffsets = new Dictionary(); - } - - //destroy the existing reference transform objects - if(missileReferenceTransforms != null) - { - for(int i = 0; i < missileReferenceTransforms.Length; i++) - { - if(missileReferenceTransforms[i]) - { - GameObject.Destroy(missileReferenceTransforms[i].gameObject); - } - } - } - - List msl = new List(); - List mtfl = new List(); - List mrl = new List(); - - foreach(var child in part.children) - { - if(child.parent != part) continue; - - MissileLauncher ml = child.FindModuleImplementing(); - - if(!ml) continue; - - Transform mTf = child.FindModelTransform("missileTransform"); - //fix incorrect hierarchy - if(!mTf) - { - Transform modelTransform = ml.part.partTransform.FindChild("model"); - - mTf = new GameObject("missileTransform").transform; - Transform[] tfchildren = new Transform[modelTransform.childCount]; - for(int i = 0; i < modelTransform.childCount; i++) - { - tfchildren[i] = modelTransform.GetChild(i); - } - mTf.parent = modelTransform; - mTf.localPosition = Vector3.zero; - mTf.localRotation = Quaternion.identity; - mTf.localScale = Vector3.one; - for(int i = 0; i < tfchildren.Length; i++) - { - Debug.Log("MissileTurret moving transform: " + tfchildren[i].gameObject.name); - tfchildren[i].parent = mTf; - } - } - - if(ml && mTf) - { - msl.Add(ml); - mtfl.Add(mTf); - Transform mRef = new GameObject().transform; - mRef.position = mTf.position; - mRef.rotation = mTf.rotation; - mRef.parent = finalTransform; - mrl.Add(mRef); - - ml.missileReferenceTransform = mTf; - ml.missileTurret = this; - - ml.decoupleForward = true; - ml.dropTime = 0; - - if(!comOffsets.ContainsKey(ml.part.name)) - { - comOffsets.Add(ml.part.name, ml.part.CoMOffset); - } - - missileCount++; - } - } - - missileChildren = msl.ToArray(); - missileTransforms = mtfl.ToArray(); - missileReferenceTransforms = mrl.ToArray(); - } - - void UpdateMissilePositions() - { - if(missileCount == 0) - { - return; - } - - for(int i = 0; i < missileChildren.Length; i++) - { - if(missileTransforms[i] && missileChildren[i] && !missileChildren[i].hasFired) - { - missileTransforms[i].position = missileReferenceTransforms[i].position; - missileTransforms[i].rotation = missileReferenceTransforms[i].rotation; - - Part missilePart = missileChildren[i].part; - Vector3 newCoMOffset = missilePart.transform.InverseTransformPoint(missileTransforms[i].TransformPoint(comOffsets[missilePart.name])); - missilePart.CoMOffset = newCoMOffset; - } - } - } - - - public void FireMissile(int index) - { - if(index < missileCount && missileChildren != null && missileChildren[index] != null) - { - PrepMissileForFire(index); - - if(weaponManager) - { - wm.SendTargetDataToMissile(missileChildren[index]); - } - missileChildren[index].FireMissile(); - StartCoroutine(MissileRailRoutine(missileChildren[index])); - if(wm) - { - wm.UpdateList(); - } - - UpdateMissileChildren(); - - timeFired = Time.time; - } - } - - public void FireMissile(MissileLauncher ml) - { - int index = IndexOfMissile(ml); - if(index >= 0) - { - Debug.Log("Firing missile index: " + index); - FireMissile(index); - } - else - { - Debug.Log("Tried to fire a missile that doesn't exist or is not attached to the turret."); - } - } - - IEnumerator MissileRailRoutine(MissileLauncher ml) - { - yield return null; - Ray ray = new Ray(ml.transform.position, ml.missileReferenceTransform.forward); - Vector3 localOrigin = turret.pitchTransform.InverseTransformPoint(ray.origin); - Vector3 localDirection = turret.pitchTransform.InverseTransformDirection(ray.direction); - float forwardSpeed = ml.decoupleSpeed; - while(ml && Vector3.SqrMagnitude(ml.transform.position - ray.origin) < railLength*railLength) - { - float thrust = ml.timeIndex < ml.boostTime ? ml.thrust : ml.cruiseThrust; - thrust = ml.timeIndex < ml.boostTime + ml.cruiseTime ? thrust : 0; - float accel = thrust / ml.part.mass; - forwardSpeed += accel * Time.fixedDeltaTime; - - ray.origin = turret.pitchTransform.TransformPoint(localOrigin); - ray.direction = turret.pitchTransform.TransformDirection(localDirection); - - Vector3 projPos = Vector3.Project(ml.vessel.transform.position - ray.origin, ray.direction) + ray.origin; - Vector3 railVel = part.rb.GetPointVelocity(projPos); - //Vector3 projVel = Vector3.Project(ml.vessel.srf_velocity-railVel, ray.direction); - - ml.vessel.SetPosition(projPos); - ml.vessel.SetWorldVelocity(railVel + (forwardSpeed*ray.direction)); - - yield return new WaitForFixedUpdate(); - - ray.origin = turret.pitchTransform.TransformPoint(localOrigin); - ray.direction = turret.pitchTransform.TransformDirection(localDirection); - } - - - } - - - void PrepMissileForFire(int index) - { - Debug.Log("Prepping missile for turret fire."); - missileTransforms[index].localPosition = Vector3.zero; - missileTransforms[index].localRotation = Quaternion.identity; - missileChildren[index].part.partTransform.position = missileReferenceTransforms[index].position; - missileChildren[index].part.partTransform.rotation = missileReferenceTransforms[index].rotation; - - missileChildren[index].dropTime = 0; - missileChildren[index].decoupleForward = true; - - missileChildren[index].part.CoMOffset = comOffsets[missileChildren[index].part.name]; - } - - public void PrepMissileForFire(MissileLauncher ml) - { - int index = IndexOfMissile(ml); - - if(index >= 0) - { - PrepMissileForFire(index); - } - else - { - Debug.Log("Tried to prep a missile for firing that doesn't exist or is not attached to the turret."); - } - } - - private int IndexOfMissile(MissileLauncher ml) - { - if(missileCount == 0) return -1; - - for(int i = 0; i < missileCount; i++) - { - if(missileChildren[i] && missileChildren[i] == ml) - { - return i; - } - } - - return -1; - } - - public bool ContainsMissileOfType(MissileLauncher ml) - { - if(!ml) return false; - if(missileCount == 0) return false; - - for(int i = 0; i < missileCount; i++) - { - if(missileChildren[i].part.name == ml.part.name) - { - return true; - } - } - return false; - } - - - } -} - diff --git a/BahaTurret/ModuleECMJammer.cs b/BahaTurret/ModuleECMJammer.cs deleted file mode 100644 index 55522badf..000000000 --- a/BahaTurret/ModuleECMJammer.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using UnityEngine; -namespace BahaTurret -{ - public class ModuleECMJammer : PartModule - { - [KSPField] - public float jammerStrength = 700; - - [KSPField] - public float lockBreakerStrength = 500; - - [KSPField] - public float rcsReductionFactor = 0.75f; - - [KSPField] - public double resourceDrain = 5; - - [KSPField] - public bool alwaysOn = false; - - [KSPField] - public bool signalSpam = true; - - [KSPField] - public bool lockBreaker = true; - - [KSPField] - public bool rcsReduction = false; - - [KSPField(isPersistant = true, guiActive = true, guiName = "Enabled")] - public bool jammerEnabled = false; - - VesselECMJInfo vesselJammer; - - [KSPAction("Enable")] - public void AGEnable(KSPActionParam param) - { - if(!jammerEnabled) - { - EnableJammer(); - } - } - - [KSPAction("Disable")] - public void AGDisable(KSPActionParam param) - { - if(jammerEnabled) - { - DisableJammer(); - } - } - - - [KSPAction("Toggle")] - public void AGToggle(KSPActionParam param) - { - Toggle(); - } - - [KSPEvent(guiActiveEditor = false, guiActive = true, guiName = "Toggle")] - public void Toggle() - { - if(jammerEnabled) - { - DisableJammer(); - } - else - { - EnableJammer(); - } - } - - public override void OnStart(StartState state) - { - base.OnStart(state); - if(HighLogic.LoadedSceneIsFlight) - { - part.force_activate(); - foreach(var wm in vessel.FindPartModulesImplementing()) - { - wm.jammers.Add(this); - } - - GameEvents.onVesselCreate.Add(OnVesselCreate); - } - } - - void OnDestroy() - { - GameEvents.onVesselCreate.Remove(OnVesselCreate); - } - - void OnVesselCreate(Vessel v) - { - EnsureVesselJammer(); - } - - public void EnableJammer() - { - EnsureVesselJammer(); - vesselJammer.AddJammer(this); - jammerEnabled = true; - } - - public void DisableJammer() - { - EnsureVesselJammer(); - - vesselJammer.RemoveJammer(this); - jammerEnabled = false; - } - - public override void OnFixedUpdate() - { - base.OnFixedUpdate(); - - if(alwaysOn && !jammerEnabled) - { - EnableJammer(); - } - - if(jammerEnabled) - { - EnsureVesselJammer(); - - DrainElectricity(); - } - } - - void EnsureVesselJammer() - { - if(!vesselJammer || vesselJammer.vessel != vessel) - { - vesselJammer = vessel.gameObject.GetComponent(); - if(!vesselJammer) - { - vesselJammer = vessel.gameObject.AddComponent(); - } - } - - vesselJammer.DelayedCleanJammerList(); - } - - - void DrainElectricity() - { - if(resourceDrain <= 0) - { - return; - } - - double drainAmount = resourceDrain * TimeWarp.fixedDeltaTime; - double chargeAvailable = part.RequestResource("ElectricCharge", drainAmount, ResourceFlowMode.ALL_VESSEL); - if(chargeAvailable < drainAmount*0.95f) - { - DisableJammer(); - } - } - - - - - } -} - diff --git a/BahaTurret/ModuleMovingPart.cs b/BahaTurret/ModuleMovingPart.cs deleted file mode 100644 index 1e1f8476b..000000000 --- a/BahaTurret/ModuleMovingPart.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; - -namespace BahaTurret -{ - public class ModuleMovingPart : PartModule - { - Transform parentTransform; - [KSPField] - public string parentTransformName = string.Empty; - - - - bool setupComplete = false; - - Part[] children; - Vector3[] localAnchors; - - public override void OnStart(StartState state) - { - base.OnStart(state); - - if(HighLogic.LoadedSceneIsFlight) - { - if(parentTransformName == string.Empty) - { - enabled = false; - return; - } - - parentTransform = part.FindModelTransform(parentTransformName); - - StartCoroutine(SetupRoutine()); - } - } - - void FixedUpdate() - { - if(setupComplete) - { - UpdateJoints(); - - } - } - - IEnumerator SetupRoutine() - { - while(vessel.packed) - { - yield return null; - } - SetupJoints(); - } - - void SetupJoints() - { - children = part.children.ToArray(); - localAnchors = new Vector3[children.Length]; - - for(int i = 0; i < children.Length; i++) - { - children[i].attachJoint.Joint.autoConfigureConnectedAnchor = false; - Vector3 connectedAnchor = children[i].attachJoint.Joint.connectedAnchor; - Vector3 worldAnchor = children[i].attachJoint.Joint.connectedBody.transform.TransformPoint(connectedAnchor); - Vector3 localAnchor = parentTransform.InverseTransformPoint(worldAnchor); - localAnchors[i] = localAnchor; - } - - setupComplete = true; - } - - void UpdateJoints() - { - for(int i = 0; i < children.Length; i++) - { - if(!children[i]) continue; - - Vector3 newWorldAnchor = parentTransform.TransformPoint(localAnchors[i]); - Vector3 newConnectedAnchor = children[i].attachJoint.Joint.connectedBody.transform.InverseTransformPoint(newWorldAnchor); - children[i].attachJoint.Joint.connectedAnchor = newConnectedAnchor; - } - } - - void OnGUI() - { - if(setupComplete) - { - for(int i = 0; i < localAnchors.Length; i++) - { - BDGUIUtils.DrawTextureOnWorldPos(parentTransform.TransformPoint(localAnchors[i]), BDArmorySettings.Instance.greenDotTexture, new Vector2(6, 6), 0); - } - } - } - } -} - diff --git a/BahaTurret/ModuleRadar.cs b/BahaTurret/ModuleRadar.cs deleted file mode 100644 index 4f2361736..000000000 --- a/BahaTurret/ModuleRadar.cs +++ /dev/null @@ -1,1044 +0,0 @@ -using UnityEngine; -using System; -using System.Collections; -using System.Collections.Generic; - -namespace BahaTurret -{ - public class ModuleRadar : PartModule - { - [KSPField] - public string radarName; - - [KSPField] - public int turretID = 0; - - - [KSPField] - public bool canLock = true; - public bool locked - { - get - { - return currLocks > 0; - } - } - - [KSPField] - public int maxLocks = 1; - public int currentLocks - { - get - { - return currLocks; - } - } - private int currLocks = 0; - - [KSPField] - public bool canScan = true; - - [KSPField] - public bool canRecieveRadarData = false; - private List linkedToVessels; - - [KSPField(isPersistant = true)] - public string linkedVesselID; - - //[KSPField] - //public string rangeIncrements = "5000,10000,20000"; - //public float[] rIncrements; - - [KSPField(isPersistant = true)] - public int rangeIndex = 99; - - public float maxRange; - - [KSPField] - public bool omnidirectional = true; - - [KSPField] - public float directionalFieldOfView = 90; - - [KSPField] - public float boresightFOV = 10; - - - [KSPField] - public float scanRotationSpeed = 120; //in degrees per second - - [KSPField] - public float lockRotationSpeed = 120; - - [KSPField] - public float lockRotationAngle = 4; - - [KSPField] - public string rotationTransformName = string.Empty; - Transform rotationTransform; - - - [KSPField(isPersistant = true)] - public bool radarEnabled = false; - - [KSPField] - public float minSignalThreshold = 90; - - [KSPField] - public float minLockedSignalThreshold = 90; - - [KSPField] - public bool canTrackWhileScan = false; - - [KSPField] - public float multiLockFOV = 30; - - [KSPField] - public int rwrThreatType = 0; - public RadarWarningReceiver.RWRThreatTypes rwrType = RadarWarningReceiver.RWRThreatTypes.SAM; - - //contacts - TargetSignatureData[] attemptedLocks; - public TargetSignatureData lockedTarget - { - get - { - if(currLocks == 0) return TargetSignatureData.noTarget; - else - { - return lockedTargets[lockedTargetIndex]; - } - } - } - public List lockedTargets; - int lockedTargetIndex = 0; - public int currentLockIndex - { - get - { - return lockedTargetIndex; - } - } - - //GUI - bool drawGUI = false; - public float signalPersistTime; - - - //scanning - [KSPField] - public bool showDirectionWhileScan = false; - [KSPField(isPersistant = true)] - public float currentAngle = 0; - float currentAngleLock = 0; - public Transform referenceTransform; - float radialScanDirection = 1; - float lockScanDirection = 1; - - - - public bool boresightScan = false; - - public List availableRadarLinks; - - //locking - [KSPField] - public float lockAttemptFOV = 2; - public float lockScanAngle = 0; - - public bool slaveTurrets = false; - - public MissileLauncher lastMissile; - - public ModuleTurret lockingTurret; - public bool lockingPitch = true; - public bool lockingYaw = true; - - private MissileFire wpmr; - public MissileFire weaponManager - { - get - { - if(wpmr == null || wpmr.vessel!=vessel) - { - wpmr = null; - foreach(var mf in vessel.FindPartModulesImplementing()) - { - wpmr = mf; - } - } - - return wpmr; - } - set - { - wpmr = value; - } - } - - public VesselRadarData vesselRadarData; - - [KSPEvent(active = true, guiActive = true, guiActiveEditor = false, guiName = "Toggle Radar")] - public void Toggle() - { - if(radarEnabled) - { - DisableRadar(); - } - else - { - EnableRadar(); - } - } - - void UpdateToggleGuiName() - { - Events["Toggle"].guiName = radarEnabled ? "Disable Radar" : "Enable Radar"; - } - - public void EnsureVesselRadarData() - { - myVesselID = vessel.id.ToString(); - - if(vesselRadarData == null || vesselRadarData.vessel!=vessel) - { - vesselRadarData = vessel.gameObject.GetComponent(); - - if(vesselRadarData == null) - { - vesselRadarData = vessel.gameObject.AddComponent(); - vesselRadarData.weaponManager = weaponManager; - } - } - } - - public void EnableRadar() - { - EnsureVesselRadarData(); - - radarEnabled = true; - foreach(var mf in vessel.FindPartModulesImplementing()) - { - weaponManager = mf; - if(vesselRadarData) - { - vesselRadarData.weaponManager = mf; - } - break; - } - - UpdateToggleGuiName(); - - - - vesselRadarData.AddRadar(this); - } - - public void DisableRadar() - { - if(locked) - { - UnlockAllTargets(); - } - - radarEnabled = false; - - foreach(var mf in vessel.FindPartModulesImplementing()) - { - //mf.radar = null; - break; - } - UpdateToggleGuiName(); - - if(vesselRadarData) - { - vesselRadarData.RemoveRadar(this); - } - - foreach(var vrd in linkedToVessels) - { - vrd.UnlinkDisabledRadar(this); - } - } - - bool unlinkOnDestroy = true; - string myVesselID; - void OnDestroy() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(vesselRadarData) - { - vesselRadarData.RemoveRadar(this); - vesselRadarData.RemoveDataFromRadar(this); - } - - if(linkedToVessels != null) - { - foreach(var vrd in linkedToVessels) - { - if(unlinkOnDestroy) - { - vrd.UnlinkDisabledRadar(this); - } - else - { - vrd.BeginWaitForUnloadedLinkedRadar(this, myVesselID); - } - } - } - } - } - - bool startupComplete = false; - public override void OnStart (StartState state) - { - base.OnStart (state); - - if(HighLogic.LoadedSceneIsFlight) - { - myVesselID = vessel.id.ToString(); - RadarUtils.SetupRadarCamera(); - - if(string.IsNullOrEmpty(radarName)) - { - radarName = part.partInfo.title; - } - - linkedToVessels = new List(); - - - - //rIncrements = Misc.ParseToFloatArray(rangeIncrements); - //rangeIndex = Mathf.Clamp(rangeIndex, 0, rIncrements.Length-1); - //maxRange = rIncrements[rIncrements.Length-1]; - signalPersistTime = omnidirectional ? 360/(scanRotationSpeed+5) : directionalFieldOfView/(scanRotationSpeed+5); - - if(rotationTransformName!=string.Empty) - { - rotationTransform = part.FindModelTransform(rotationTransformName); - } - - - - //lockedTarget = TargetSignatureData.noTarget; - - - - attemptedLocks = new TargetSignatureData[3]; - TargetSignatureData.ResetTSDArray(ref attemptedLocks); - - lockedTargets = new List(); - - referenceTransform = (new GameObject()).transform; - referenceTransform.parent = transform; - referenceTransform.localPosition = Vector3.zero; - - foreach(var tur in part.FindModulesImplementing()) - { - if(tur.turretID == turretID) - { - lockingTurret = tur; - break; - } - } - - rwrType = (RadarWarningReceiver.RWRThreatTypes) rwrThreatType; - - - foreach(var wm in vessel.FindPartModulesImplementing()) - { - wm.radars.Add(this); - } - - GameEvents.onVesselGoOnRails.Add(OnGoOnRails); - - - EnsureVesselRadarData(); - - StartCoroutine(StartUpRoutine()); - } - - if(HighLogic.LoadedSceneIsEditor) - { - foreach(var tur in part.FindModulesImplementing()) - { - if(tur.turretID == turretID) - { - lockingTurret = tur; - break; - } - } - - if(lockingTurret) - { - lockingTurret.Fields["minPitch"].guiActiveEditor = false; - lockingTurret.Fields["maxPitch"].guiActiveEditor = false; - lockingTurret.Fields["yawRange"].guiActiveEditor = false; - } - } - } - - void OnGoOnRails(Vessel v) - { - if(v == vessel) - { - unlinkOnDestroy = false; - myVesselID = vessel.id.ToString(); - } - } - - IEnumerator StartUpRoutine() - { - Debug.Log("StartupRoutine: " + radarName+" enabled: "+radarEnabled); - while(!FlightGlobals.ready || vessel.packed) - { - yield return null; - } - - yield return new WaitForFixedUpdate(); - - if (radarEnabled) - { - EnableRadar(); - } - - /* - if(linked) - { - foreach(var v in FlightGlobals.Vessels) - { - if(v.id.ToString() == linkedVesselID) - { - foreach(var mr in v.FindPartModulesImplementing()) - { - if(mr.radarEnabled) - { - //LinkToRadar(mr); - break; - } - } - break; - } - } - if(!linkedRadar) - { - Debug.Log("Radar was linked, but linked radar doesn't exist."); - UnlinkRadar(); - } - - } - */ - yield return null; - if(!vesselRadarData.hasLoadedExternalVRDs) - { - RecoverLinkedVessels(); - vesselRadarData.hasLoadedExternalVRDs = true; - } - - UpdateToggleGuiName(); - - - startupComplete = true; - } - - // Update is called once per frame - void Update () - { - if(HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && radarEnabled) - { - if(omnidirectional) - { - referenceTransform.position = vessel.transform.position; - referenceTransform.rotation = Quaternion.LookRotation(VectorUtils.GetNorthVector(transform.position, vessel.mainBody), VectorUtils.GetUpDirection(transform.position)); - } - else - { - referenceTransform.position = vessel.transform.position; - referenceTransform.rotation = Quaternion.LookRotation(part.transform.up, VectorUtils.GetUpDirection(referenceTransform.position)); - } - //UpdateInputs(); - } - - drawGUI = (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && radarEnabled && vessel.isActiveVessel && BDArmorySettings.GAME_UI_ENABLED && !MapView.MapIsEnabled); - - //UpdateSlaveData(); - } - - void FixedUpdate() - { - if(HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && startupComplete) - { - if(!vessel.IsControllable && radarEnabled) - { - DisableRadar(); - } - - if(radarEnabled) - { - if(locked) - { - for(int i = 0; i < lockedTargets.Count; i++) - { - UpdateLock(i); - } - - if (canTrackWhileScan) - { - Scan(); - } - } - else if(boresightScan) - { - BoresightScan(); - } - else if(canScan) - { - Scan (); - } - - - } - } - } - - void UpdateSlaveData() - { - if(slaveTurrets && weaponManager) - { - weaponManager.slavingTurrets = true; - if(locked) - { - weaponManager.slavedPosition = lockedTarget.predictedPosition; - weaponManager.slavedVelocity = lockedTarget.velocity; - weaponManager.slavedAcceleration = lockedTarget.acceleration; - } - } - } - - void LateUpdate() - { - if (HighLogic.LoadedSceneIsFlight && (canScan || canLock)) - { - UpdateModel (); - } - } - - - - void UpdateModel() - { - //model rotation - - if(radarEnabled) - { - if(rotationTransform && canScan) - { - Vector3 direction; - if(locked) - { - direction = Quaternion.AngleAxis(canTrackWhileScan ? currentAngle : lockScanAngle, referenceTransform.up) * referenceTransform.forward; - } - else - { - direction = Quaternion.AngleAxis(currentAngle, referenceTransform.up) * referenceTransform.forward; - } - - Vector3 localDirection = Vector3.ProjectOnPlane(rotationTransform.parent.InverseTransformDirection(direction), Vector3.up); - if(localDirection != Vector3.zero) - { - rotationTransform.localRotation = Quaternion.Lerp(rotationTransform.localRotation, Quaternion.LookRotation(localDirection, Vector3.up), 10 * TimeWarp.fixedDeltaTime); - } - - } - - //lock turret - if(lockingTurret && canLock) - { - if(locked) - { - lockingTurret.AimToTarget(lockedTarget.predictedPosition, lockingPitch, lockingYaw); - } - else - { - lockingTurret.ReturnTurret(); - } - } - } - else - { - if(rotationTransform) - { - rotationTransform.localRotation = Quaternion.Lerp(rotationTransform.localRotation, Quaternion.identity, 5 * TimeWarp.fixedDeltaTime); - } - - if(lockingTurret) - { - lockingTurret.ReturnTurret(); - } - } - - } - - public float leftLimit; - public float rightLimit; - - void Scan() - { - float angleDelta = scanRotationSpeed*Time.fixedDeltaTime; - //RadarUtils.ScanInDirection(weaponManager, currentAngle, referenceTransform, angleDelta, vessel.transform.position, minSignalThreshold, ref contacts, signalPersistTime, true, rwrType, true); - RadarUtils.UpdateRadarLock(weaponManager, currentAngle, referenceTransform, angleDelta, vessel.transform.position, minSignalThreshold, this, true, rwrType, true); - - if(omnidirectional) - { - currentAngle = Mathf.Repeat(currentAngle+angleDelta, 360); - } - else - { - currentAngle += radialScanDirection*angleDelta; - - if(locked) - { - float targetAngle = VectorUtils.SignedAngle(referenceTransform.forward, Vector3.ProjectOnPlane(lockedTarget.position - referenceTransform.position, referenceTransform.up), referenceTransform.right); - leftLimit = Mathf.Clamp(targetAngle - (multiLockFOV / 2), -directionalFieldOfView / 2, directionalFieldOfView / 2); - rightLimit = Mathf.Clamp(targetAngle + (multiLockFOV / 2), -directionalFieldOfView / 2, directionalFieldOfView / 2); - - if(radialScanDirection < 0 && currentAngle < leftLimit) - { - currentAngle = leftLimit; - radialScanDirection = 1; - } - else if(radialScanDirection > 0 && currentAngle > rightLimit) - { - currentAngle = rightLimit; - radialScanDirection = -1; - } - } - else - { - if(Mathf.Abs(currentAngle) > directionalFieldOfView / 2) - { - currentAngle = Mathf.Sign(currentAngle) * directionalFieldOfView / 2; - radialScanDirection = -radialScanDirection; - } - } - } - } - - - - public bool TryLockTarget(Vector3 position) - { - if(!canLock) - { - return false; - } - Debug.Log ("Trying to radar lock target"); - - if(currentLocks == maxLocks) - { - Debug.Log("This radar ("+ radarName +") already has the maximum allowed targets locked."); - return false; - } - - - Vector3 targetPlanarDirection = Vector3.ProjectOnPlane(position-referenceTransform.position, referenceTransform.up); - float angle = Vector3.Angle(targetPlanarDirection, referenceTransform.forward); - if(referenceTransform.InverseTransformPoint(position).x < 0) - { - angle = -angle; - } - //TargetSignatureData.ResetTSDArray(ref attemptedLocks); - RadarUtils.UpdateRadarLock(weaponManager, angle, referenceTransform, lockAttemptFOV, referenceTransform.position, minLockedSignalThreshold, ref attemptedLocks, signalPersistTime, true, rwrType, true); - - for(int i = 0; i < attemptedLocks.Length; i++) - { - if(attemptedLocks[i].exists && (attemptedLocks[i].predictedPosition-position).sqrMagnitude < 40*40) - { - if(!locked && !omnidirectional) - { - float targetAngle = VectorUtils.SignedAngle(referenceTransform.forward, Vector3.ProjectOnPlane(attemptedLocks[i].position - referenceTransform.position, referenceTransform.up), referenceTransform.right); - currentAngle = targetAngle; - } - lockedTargets.Add(attemptedLocks[i]); - currLocks = lockedTargets.Count; - Debug.Log ("- Acquired lock on target."); - vesselRadarData.AddRadarContact(this, lockedTarget, true); - vesselRadarData.UpdateLockedTargets(); - return true; - } - } - - Debug.Log ("- Failed to lock on target."); - return false; - } - - - void BoresightScan() - { - if(locked) - { - boresightScan = false; - return; - } - - currentAngle = Mathf.Lerp(currentAngle, 0, 0.08f); - RadarUtils.UpdateRadarLock (new Ray (transform.position, transform.up), boresightFOV, minLockedSignalThreshold, ref attemptedLocks, Time.fixedDeltaTime, true, rwrType, true); - - - for(int i = 0; i < attemptedLocks.Length; i++) - { - if(attemptedLocks[i].exists && attemptedLocks[i].age < 0.1f) - { - TryLockTarget(attemptedLocks[i].predictedPosition); - /* - locked = true; - //lockedTarget = attemptedLocks[i]; - lockedTargets = new List(); - lockedTargets.Add(attemptedLocks[i]); - lockedTargetIndex = 0; - Debug.Log ("- Acquired lock on target."); - */ - boresightScan = false; - return; - } - } - } - - - int snapshotTicker = 0; - void UpdateLock(int index) - { - TargetSignatureData lockedTarget = lockedTargets[index]; - - Vector3 targetPlanarDirection = Vector3.ProjectOnPlane(lockedTarget.predictedPosition-referenceTransform.position, referenceTransform.up); - float lookAngle = Vector3.Angle(targetPlanarDirection, referenceTransform.forward); - if(referenceTransform.InverseTransformPoint(lockedTarget.predictedPosition).x < 0) - { - lookAngle = -lookAngle; - } - - if(omnidirectional) - { - if(lookAngle < 0) lookAngle += 360; - } - - - lockScanAngle = lookAngle + currentAngleLock; - if (!canTrackWhileScan && index == lockedTargetIndex) - { - currentAngle = lockScanAngle; - } - float angleDelta = lockRotationSpeed*Time.fixedDeltaTime; - float lockedSignalPersist = lockRotationAngle/lockRotationSpeed; - //RadarUtils.ScanInDirection(lockScanAngle, referenceTransform, angleDelta, referenceTransform.position, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist); - bool radarSnapshot = (snapshotTicker > 30); - if(radarSnapshot) - { - snapshotTicker = 0; - } - else - { - snapshotTicker++; - } - //RadarUtils.ScanInDirection (new Ray (referenceTransform.position, lockedTarget.predictedPosition - referenceTransform.position), lockRotationAngle * 2, minLockedSignalThreshold, ref attemptedLocks, lockedSignalPersist, true, rwrType, radarSnapshot); - - if(Vector3.Angle(lockedTarget.position - referenceTransform.position, this.lockedTarget.position - referenceTransform.position) > multiLockFOV / 2) - { - UnlockTargetAt(index, true); - return; - } - - RadarUtils.UpdateRadarLock(new Ray(referenceTransform.position, lockedTarget.predictedPosition - referenceTransform.position), lockedTarget.predictedPosition, lockRotationAngle * 2, minLockedSignalThreshold, this, true, radarSnapshot, lockedSignalPersist, true, index, lockedTarget.vessel); - - /* - TargetSignatureData prevLock = lockedTarget; - lockedTarget = TargetSignatureData.noTarget; - for(int i = 0; i < attemptedLocks.Length; i++) - { - if(attemptedLocks[i].exists && (attemptedLocks[i].predictedPosition-prevLock.predictedPosition).sqrMagnitude < Mathf.Pow(20,2) && attemptedLocks[i].age < 2*lockedSignalPersist) - { - lockedTarget = attemptedLocks[i]; - break; - } - } - - if(!lockedTarget.exists) //if failed to maintain lock, get lock data from linked radar - { - if(linked && linkedRadar && linkedRadar.locked && (linkedRadar.lockedTarget.predictedPosition-prevLock.predictedPosition).sqrMagnitude < Mathf.Pow(20,2)) - { - lockedTarget = linkedRadar.lockedTarget; - //if(lockedTarget.exists) return; - } - } - */ - - //if still failed or out of FOV, unlock. - if(!lockedTarget.exists || (!omnidirectional && Vector3.Angle(lockedTarget.position-referenceTransform.position, transform.up) > directionalFieldOfView/2)) - { - //UnlockAllTargets(); - UnlockTargetAt(index, true); - return; - } - - //unlock if over-jammed - if(lockedTarget.vesselJammer && lockedTarget.vesselJammer.lockBreakStrength > lockedTarget.signalStrength*lockedTarget.vesselJammer.rcsReductionFactor) - { - //UnlockAllTargets(); - UnlockTargetAt(index, true); - return; - } - - - //cycle scan direction - if(index == lockedTargetIndex) - { - currentAngleLock += lockScanDirection * angleDelta; - if(Mathf.Abs(currentAngleLock) > lockRotationAngle / 2) - { - currentAngleLock = Mathf.Sign(currentAngleLock) * lockRotationAngle / 2; - lockScanDirection = -lockScanDirection; - } - } - } - - - - public void UnlockAllTargets() - { - if(!locked) return; - - lockedTargets.Clear(); - currLocks = 0; - lockedTargetIndex = 0; - - - if(vesselRadarData) - { - vesselRadarData.UnlockAllTargetsOfRadar(this); - } - } - - public void SetActiveLock(TargetSignatureData target) - { - for(int i = 0; i < lockedTargets.Count; i++) - { - if(target.vessel == lockedTargets[i].vessel) - { - lockedTargetIndex = i; - return; - } - } - } - - public void UnlockTargetAt(int index, bool tryRelock = false) - { - Vessel rVess = lockedTargets[index].vessel; - - if(tryRelock) - { - UnlockTargetAt(index, false); - if(rVess) - { - StartCoroutine(RetryLockRoutine(rVess)); - } - return; - } - - - lockedTargets.RemoveAt(index); - currLocks = lockedTargets.Count; - if(lockedTargetIndex > index) - { - lockedTargetIndex--; - } - - lockedTargetIndex = Mathf.Clamp(lockedTargetIndex, 0, currLocks - 1); - lockedTargetIndex = Mathf.Max(lockedTargetIndex, 0); - - if(vesselRadarData) - { - //vesselRadarData.UnlockTargetAtPosition(position); - vesselRadarData.RemoveVesselFromTargets(rVess); - } - } - - IEnumerator RetryLockRoutine(Vessel v) - { - yield return null; - vesselRadarData.TryLockTarget(v); - } - - public void UnlockTargetVessel(Vessel v) - { - for(int i = 0; i < lockedTargets.Count; i++) - { - if(lockedTargets[i].vessel == v) - { - UnlockTargetAt(i); - return; - } - } - } - - /* - public void UnlockTargetAtPosition(Vector3 position) - { - for(int i = 0; i < lockedTargets.Count; i++) - { - if(Vector3.SqrMagnitude(lockedTargets[i].position - position) < 10) - { - UnlockTargetAt(i); - return; - } - } - } - */ - - void SlaveTurrets() - { - foreach (var mtc in vessel.FindPartModulesImplementing()) - { - mtc.slaveTurrets = false; - } - - foreach (var rad in vessel.FindPartModulesImplementing()) - { - rad.slaveTurrets = false; - } - - slaveTurrets = true; - } - - void UnslaveTurrets() - { - foreach (var mtc in vessel.FindPartModulesImplementing()) - { - mtc.slaveTurrets = false; - } - - foreach (var rad in vessel.FindPartModulesImplementing()) - { - rad.slaveTurrets = false; - } - - if(weaponManager) - { - weaponManager.slavingTurrets = false; - } - - slaveTurrets = false; - } - - public void UpdateLockedTargetInfo(TargetSignatureData newData) - { - int index = -1; - for(int i = 0; i < lockedTargets.Count; i++) - { - if(lockedTargets[i].vessel == newData.vessel) - { - index = i; - break; - } - } - - if(index >= 0) - { - lockedTargets[index] = newData; - } - } - - public void ReceiveContactData(TargetSignatureData contactData, bool _locked) - { - if(vesselRadarData) - { - vesselRadarData.AddRadarContact(this, contactData, _locked); - } - - foreach(var vrd in linkedToVessels) - { - if(vrd && vrd.canReceiveRadarData && vrd.vessel!=contactData.vessel) - { - vrd.AddRadarContact(this, contactData, _locked); - } - } - } - - public void AddExternalVRD(VesselRadarData vrd) - { - if(!linkedToVessels.Contains(vrd)) - { - linkedToVessels.Add(vrd); - } - } - - public void RemoveExternalVRD(VesselRadarData vrd) - { - linkedToVessels.Remove(vrd); - } - - void OnGUI() - { - if(drawGUI) - { - if(boresightScan) - { - BDGUIUtils.DrawTextureOnWorldPos(transform.position + (3500 * transform.up), BDArmorySettings.Instance.dottedLargeGreenCircle, new Vector2(156, 156), 0); - } - } - } - - - - - public void RecoverLinkedVessels() - { - string[] vesselIDs = linkedVesselID.Split(new char[]{ ',' }); - for(int i = 0; i < vesselIDs.Length; i++) - { - StartCoroutine(RecoverLinkedVesselRoutine(vesselIDs[i])); - } - } - - IEnumerator RecoverLinkedVesselRoutine(string vesselID) - { - while(true) - { - foreach(var v in BDATargetManager.LoadedVessels) - { - if(!v || !v.loaded || v==vessel) continue; - if(v.id.ToString() == vesselID) - { - VesselRadarData vrd = v.GetComponent(); - if(vrd) - { - StartCoroutine(RelinkVRDWhenReadyRoutine(vrd)); - yield break; - } - } - } - - yield return new WaitForSeconds(0.5f); - } - } - - IEnumerator RelinkVRDWhenReadyRoutine(VesselRadarData vrd) - { - while(!vrd.radarsReady || vrd.vessel.packed) - { - yield return null; - } - yield return null; - vesselRadarData.LinkVRD(vrd); - Debug.Log("Radar data link recovered: Local - " + vessel.vesselName + ", External - " + vrd.vessel.vesselName); - } - - - - ////////////////END GUI - - - - } -} - diff --git a/BahaTurret/ModuleTargetingCamera.cs b/BahaTurret/ModuleTargetingCamera.cs deleted file mode 100644 index de5d8a4c8..000000000 --- a/BahaTurret/ModuleTargetingCamera.cs +++ /dev/null @@ -1,1479 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections; -using UnityEngine; -namespace BahaTurret -{ - public class ModuleTargetingCamera : PartModule - { - [KSPField] - public string cameraTransformName; - public Transform cameraParentTransform; - - [KSPField] - public string eyeHolderTransformName; - Transform eyeHolderTransform; - - [KSPField] - public float maxRayDistance = 15500; - - [KSPField] - public float gimbalLimit = 120; - public bool gimbalLimitReached = false; - - [KSPField] - public bool rollCameraModel = false; - - [KSPField(isPersistant = true)] - public bool cameraEnabled = false; - - float fov - { - get - { - return zoomFovs[currentFovIndex]; - } - } - - [KSPField] - public string zoomFOVs = "40,15,3,1"; - float[] zoomFovs;// = new float[]{40,15,3,1f}; - - [KSPField(isPersistant = true)] - public int currentFovIndex = 0; - - [KSPField(isPersistant = true)] - public bool slaveTurrets = false; - - [KSPField(isPersistant = true)] - public bool CoMLock = false; - - public bool radarLock = false; - - float controlPanelHeight = 84;//80 - - [KSPField(isPersistant = true)] - public bool groundStabilized = false; - /// - /// Point on surface that camera is focused and stabilized on. - /// - public Vector3 groundTargetPosition; - - [KSPField(isPersistant = true)] - public double savedLat; - - [KSPField(isPersistant = true)] - public double savedLong; - - [KSPField(isPersistant = true)] - public double savedAlt; - - public Vector3 bodyRelativeGTP - { - get - { - return new Vector3d(savedLat, savedLong, savedAlt); - } - - set - { - savedLat = value.x; - savedLong = value.y; - savedAlt = value.z; - } - } - - bool resetting = false; - - - public bool surfaceDetected = false; - /// - /// Point where camera is focused, regardless of whether surface is detected or not. - /// - public Vector3 targetPointPosition; - - [KSPField(isPersistant = true)] - public bool nvMode = false; - - //GUI - public static ModuleTargetingCamera activeCam; - public static bool camRectInitialized = false; - public static bool windowIsOpen = false; - public static Rect camWindowRect; - float camImageSize = 360; - bool resizing = false; - - bool slewedCamera = false; - float finalSlewSpeed; - Vector2 slewInput = Vector2.zero; - - - Texture2D riTex; - Texture2D rollIndicatorTexture - { - get - { - if(!riTex) - { - riTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/rollIndicator", false); - } - return riTex; - } - } - - Texture2D rrTex; - Texture2D rollReferenceTexture - { - get - { - if(!rrTex) - { - rrTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/rollReference", false); - } - return rrTex; - } - } - - private MissileFire wpmr; - public MissileFire weaponManager - { - get - { - if(wpmr == null || wpmr.vessel!=vessel) - { - wpmr = null; - foreach(var mf in vessel.FindPartModulesImplementing()) - { - wpmr = mf; - } - } - - return wpmr; - } - } - - - [KSPEvent(guiName = "Enable", guiActive = true, guiActiveEditor = false)] - public void EnableButton() - { - EnableCamera(); - } - - [KSPAction("Enable")] - public void AGEnable(KSPActionParam param) - { - EnableCamera(); - } - - public void ToggleCamera() - { - if(cameraEnabled) - { - DisableCamera(); - } - else - { - EnableCamera(); - } - } - - public void EnableCamera() - { - if(!TargetingCamera.Instance) - { - Debug.Log ("Tried to enable targeting camera, but camera instance is null."); - return; - } - if(vessel.isActiveVessel) - { - activeCam = this; - windowIsOpen = true; - TargetingCamera.Instance.EnableCamera(cameraParentTransform); - TargetingCamera.Instance.nvMode = nvMode; - TargetingCamera.Instance.SetFOV(fov); - RefreshWindowSize(); - } - - cameraEnabled = true; - - if(weaponManager) - { - weaponManager.mainTGP = this; - } - - BDATargetManager.RegisterLaserPoint(this); - } - - public void DisableCamera() - { - cameraEnabled = false; - groundStabilized = false; - - if(slaveTurrets) - { - UnslaveTurrets(); - } - //StopResetting(); - - - - if(vessel.isActiveVessel) - { - if(!TargetingCamera.Instance) - { - Debug.Log ("Tried to disable targeting camera, but camera instance is null."); - return; - } - - TargetingCamera.Instance.DisableCamera(); - if(ModuleTargetingCamera.activeCam == this) - { - ModuleTargetingCamera.activeCam = FindNextActiveCamera(); - if(!ModuleTargetingCamera.activeCam) - { - windowIsOpen = false; - } - } - else - { - windowIsOpen = false; - } - - - - } - BDATargetManager.ActiveLasers.Remove(this); - - if(weaponManager && weaponManager.mainTGP == this) - { - weaponManager.mainTGP = FindNextActiveCamera(); - } - } - - ModuleTargetingCamera FindNextActiveCamera() - { - foreach(var mtc in vessel.FindPartModulesImplementing()) - { - if(mtc.cameraEnabled) - { - mtc.EnableCamera(); - return mtc; - } - } - - return null; - } - - public override void OnAwake () - { - base.OnAwake (); - - if(HighLogic.LoadedSceneIsFlight) - { - if(!TargetingCamera.Instance) - { - (new GameObject("TargetingCameraObject")).AddComponent(); - } - } - } - - - - public override void OnStart (StartState state) - { - base.OnStart (state); - - if(HighLogic.LoadedSceneIsFlight) - { - //GUI setup - if(!camRectInitialized) - { - float windowWidth = camImageSize+16; - float windowHeight = camImageSize+8+controlPanelHeight; - - camWindowRect = new Rect(Screen.width-windowWidth, Screen.height-windowHeight, windowWidth, windowHeight); - camRectInitialized = true; - } - - cameraParentTransform = part.FindModelTransform(cameraTransformName); - - eyeHolderTransform = part.FindModelTransform(eyeHolderTransformName); - - - - ParseFovs(); - UpdateSlewRate(); - - GameEvents.onVesselCreate.Add(Disconnect); - - - if(cameraEnabled) - { - Debug.Log("saved gtp: " + bodyRelativeGTP); - DelayedEnable(); - } - - foreach(var wm in vessel.FindPartModulesImplementing()) - { - wm.targetingPods.Add(this); - } - } - } - - void Disconnect(Vessel v) - { - if(weaponManager && vessel) - { - if(weaponManager.vessel != vessel) - { - if(slaveTurrets) - { - weaponManager.slavingTurrets = false; - } - } - } - } - - public void DelayedEnable() - { - StartCoroutine(DelayedEnableRoutine()); - } - - bool delayedEnabling = false; - IEnumerator DelayedEnableRoutine() - { - if(delayedEnabling) yield break; - delayedEnabling = true; - - Vector3d savedGTP = bodyRelativeGTP; - Debug.Log("saved gtp: " + Misc.FormattedGeoPos(savedGTP, true)); - Debug.Log("groundStabilized: " + groundStabilized); - - while(TargetingCamera.Instance == null) - { - yield return null; - } - while(!FlightGlobals.ready) - { - yield return null; - } - while(FlightCamera.fetch == null) - { - yield return null; - } - while(FlightCamera.fetch.mainCamera == null) - { - yield return null; - } - while(vessel.packed) - { - yield return null; - } - - while(vessel.mainBody == null) - { - yield return null; - } - - EnableCamera(); - if(groundStabilized) - { - Debug.Log("Camera delayed enabled"); - groundTargetPosition = VectorUtils.GetWorldSurfacePostion(savedGTP, vessel.mainBody);// vessel.mainBody.GetWorldSurfacePosition(bodyRelativeGTP.x, bodyRelativeGTP.y, bodyRelativeGTP.z); - Vector3 lookVector = groundTargetPosition-cameraParentTransform.position; - PointCameraModel(lookVector); - GroundStabilize(); - } - delayedEnabling = false; - - Debug.Log("post load saved gtp: " + bodyRelativeGTP); - } - - void PointCameraModel(Vector3 lookVector) - { - - Vector3 worldUp = VectorUtils.GetUpDirection(cameraParentTransform.position); - if(rollCameraModel) - { - cameraParentTransform.rotation = Quaternion.LookRotation(lookVector, worldUp); - } - else - { - Vector3 camUp = cameraParentTransform.up; - if(eyeHolderTransform) camUp = Vector3.Cross(cameraParentTransform.forward, eyeHolderTransform.right); - cameraParentTransform.rotation = Quaternion.LookRotation(lookVector, camUp); - if(vessel.isActiveVessel && activeCam == this && TargetingCamera.cameraTransform) - { - TargetingCamera.cameraTransform.rotation = Quaternion.LookRotation(cameraParentTransform.forward, worldUp); - } - } - - } - - - void Update() - { - if(HighLogic.LoadedSceneIsFlight) - { - - - if(cameraEnabled && TargetingCamera.ReadyForUse && vessel.IsControllable) - { - if(delayedEnabling) return; - - - if(!TargetingCamera.Instance || FlightGlobals.currentMainBody == null) - { - return; - } - - if(activeCam == this) - { - if(zoomFovs!=null) - { - TargetingCamera.Instance.SetFOV(fov); - } - } - - - - if(radarLock) - { - UpdateRadarLock(); - } - - if(groundStabilized) - { - groundTargetPosition = VectorUtils.GetWorldSurfacePostion(bodyRelativeGTP, vessel.mainBody);//vessel.mainBody.GetWorldSurfacePosition(bodyRelativeGTP.x, bodyRelativeGTP.y, bodyRelativeGTP.z); - Vector3 lookVector = groundTargetPosition-cameraParentTransform.position; - //cameraParentTransform.rotation = Quaternion.LookRotation(lookVector); - PointCameraModel(lookVector); - } - - - - Vector3 lookDirection = cameraParentTransform.forward; - if(Vector3.Angle(lookDirection, cameraParentTransform.parent.forward) > gimbalLimit) - { - lookDirection = Vector3.RotateTowards(cameraParentTransform.transform.parent.forward, lookDirection, gimbalLimit*Mathf.Deg2Rad, 0); - gimbalLimitReached = true; - } - else - { - gimbalLimitReached = false; - } - - if(!groundStabilized || gimbalLimitReached) - { - PointCameraModel(lookDirection); - } - - - if(eyeHolderTransform) - { - Vector3 projectedForward = Vector3.ProjectOnPlane(cameraParentTransform.forward, eyeHolderTransform.parent.up); - if(projectedForward!=Vector3.zero) - { - eyeHolderTransform.rotation = Quaternion.LookRotation(projectedForward, eyeHolderTransform.parent.up); - } - } - - UpdateControls(); - UpdateSlaveData(); - } - - } - } - - public override void OnFixedUpdate() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(cameraEnabled && !vessel.packed && !vessel.IsControllable) - { - DisableCamera(); - } - } - } - - void FixedUpdate() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(delayedEnabling) return; - - if(cameraEnabled) - { - GetHitPoint(); - } - } - } - - void UpdateKeyInputs() - { - if(!vessel.isActiveVessel) - { - return; - } - - if(BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_LEFT)) - { - slewInput.x = -1; - } - else if(BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_RIGHT)) - { - slewInput.x = 1; - } - - if(BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_UP)) - { - slewInput.y = 1; - } - else if(BDInputUtils.GetKey(BDInputSettingsFields.TGP_SLEW_DOWN)) - { - slewInput.y = -1; - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_IN)) - { - ZoomIn(); - } - else if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_OUT)) - { - ZoomOut(); - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_LOCK)) - { - if(groundStabilized) - { - ClearTarget(); - } - else - { - GroundStabilize(); - } - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_NV)) - { - ToggleNV(); - } - - if(groundStabilized && BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_SEND_GPS)) - { - SendGPS(); - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_COM)) - { - CoMLock = !CoMLock; - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_RADAR)) - { - radarLock = !radarLock; - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_TURRETS)) - { - if(slaveTurrets) - { - UnslaveTurrets(); - } - else - { - SlaveTurrets(); - } - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_TO_GPS)) - { - PointToGPSTarget(); - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.TGP_RESET)) - { - ResetCameraButton(); - } - } - - void ToggleNV() - { - nvMode = !nvMode; - TargetingCamera.Instance.nvMode = nvMode; - } - - void UpdateControls() - { - UpdateKeyInputs(); - UpdateSlewRate(); - if(slewInput != Vector2.zero) - { - SlewCamera(slewInput); - } - slewInput = Vector2.zero; - } - - - void UpdateSlewRate() - { - if(slewedCamera) - { - finalSlewSpeed = Mathf.Clamp(finalSlewSpeed + (0.5f * (fov/60)), 0, 80 * fov/60); - slewedCamera = false; - } - else - { - finalSlewSpeed = 15 * fov/60; - } - } - - void UpdateRadarLock() - { - if(weaponManager && weaponManager.vesselRadarData && weaponManager.vesselRadarData.locked) - { - RadarDisplayData tgt = weaponManager.vesselRadarData.lockedTargetData; - Vector3 radarTargetPos = tgt.targetData.predictedPosition + (tgt.targetData.velocity*Time.fixedDeltaTime); - Vector3 targetDirection = radarTargetPos - cameraParentTransform.position; - - //Quaternion lookRotation = Quaternion.LookRotation(radarTargetPos-cameraParentTransform.position, VectorUtils.GetUpDirection(cameraParentTransform.position)); - if(Vector3.Angle(radarTargetPos - cameraParentTransform.position, cameraParentTransform.forward) < 0.5f) - { - //cameraParentTransform.rotation = lookRotation; - if(tgt.vessel) - { - targetDirection = ((tgt.vessel.CoM+(tgt.vessel.rb_velocity*Time.fixedDeltaTime)) - cameraParentTransform.transform.position); - } - PointCameraModel(targetDirection); - GroundStabilize(); - } - else - { - if(groundStabilized) - { - ClearTarget(); - } - //lookRotation = Quaternion.RotateTowards(cameraParentTransform.rotation, lookRotation, 120*Time.fixedDeltaTime); - Vector3 rotateTwdDirection = Vector3.RotateTowards(cameraParentTransform.forward, targetDirection, 300*Time.fixedDeltaTime*Mathf.Deg2Rad, 0); - PointCameraModel(rotateTwdDirection); - } - } - else - { - //radarLock = false; - } - } - - void OnGUI() - { - if (HighLogic.LoadedSceneIsFlight && !MapView.MapIsEnabled && BDArmorySettings.GAME_UI_ENABLED && !delayedEnabling) - { - if (cameraEnabled && vessel.isActiveVessel && FlightGlobals.ready) - { - //window - if (activeCam == this && TargetingCamera.ReadyForUse) - { - camWindowRect = GUI.Window (125452, camWindowRect, CamWindow, string.Empty, HighLogic.Skin.window); - BDGUIUtils.UseMouseEventInRect(camWindowRect); - } - - //locked target icon - if(groundStabilized) - { - BDGUIUtils.DrawTextureOnWorldPos(groundTargetPosition, BDArmorySettings.Instance.greenPointCircleTexture, new Vector3(20, 20), 0); - } - else - { - BDGUIUtils.DrawTextureOnWorldPos(targetPointPosition, BDArmorySettings.Instance.greenCircleTexture, new Vector3(18, 18), 0); - } - } - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(500, 500, 500, 500), "Slew rate: " + finalSlewSpeed); - } - - if(BDArmorySettings.DRAW_DEBUG_LINES) - { - if(groundStabilized) - { - BDGUIUtils.DrawLineBetweenWorldPositions(cameraParentTransform.position, groundTargetPosition, 2, Color.red); - } - else - { - BDGUIUtils.DrawLineBetweenWorldPositions(cameraParentTransform.position, targetPointPosition, 2, Color.red); - } - } - } - - - - } - - void CamWindow(int windowID) - { - if(!TargetingCamera.Instance) - { - return; - } - - windowIsOpen = true; - - GUI.DragWindow(new Rect(0,0,camImageSize+16, camImageSize+8)); - - Rect imageRect = new Rect(8,20,camImageSize,camImageSize); - GUI.DrawTexture(imageRect, TargetingCamera.Instance.targetCamRenderTexture, ScaleMode.StretchToFill, false); - GUI.DrawTexture(imageRect, TargetingCamera.Instance.ReticleTexture, ScaleMode.StretchToFill, true); - - float controlsStartY = 24 + camImageSize + 4; - - //slew buttons - float slewStartX = 8; - float slewSize = (controlPanelHeight/3) - 8; - Rect slewUpRect = new Rect(slewStartX + slewSize, controlsStartY, slewSize, slewSize); - Rect slewDownRect = new Rect(slewStartX + slewSize, controlsStartY + (2*slewSize), slewSize, slewSize); - Rect slewLeftRect = new Rect(slewStartX, controlsStartY + slewSize, slewSize, slewSize); - Rect slewRightRect = new Rect(slewStartX + (2*slewSize), controlsStartY+slewSize, slewSize, slewSize); - if(GUI.RepeatButton(slewUpRect, "^", HighLogic.Skin.button)) - { - //SlewCamera(Vector3.up); - slewInput.y = 1; - } - if(GUI.RepeatButton(slewDownRect, "v", HighLogic.Skin.button)) - { - //SlewCamera(Vector3.down); - slewInput.y = -1; - } - if(GUI.RepeatButton(slewLeftRect, "<", HighLogic.Skin.button)) - { - //SlewCamera(Vector3.left); - slewInput.x = -1; - } - if(GUI.RepeatButton(slewRightRect, ">", HighLogic.Skin.button)) - { - //SlewCamera(Vector3.right); - slewInput.x = 1; - } - - //zoom buttons - float zoomStartX = 8 + (3*slewSize) + 4; - Rect zoomInRect = new Rect(zoomStartX, controlsStartY, 3*slewSize, slewSize); - Rect zoomOutRect = new Rect(zoomStartX, controlsStartY + (2*slewSize), 3*slewSize, slewSize); - GUIStyle disabledStyle = new GUIStyle(); - disabledStyle.alignment = TextAnchor.MiddleCenter; - disabledStyle.normal.textColor = Color.white; - if(currentFovIndex < zoomFovs.Length-1) - { - if(GUI.Button(zoomInRect, "In", HighLogic.Skin.button)) - { - ZoomIn(); - } - } - else - { - GUI.Label(zoomInRect, "(In)", disabledStyle); - } - if(currentFovIndex > 0) - { - if(GUI.Button(zoomOutRect, "Out", HighLogic.Skin.button)) - { - ZoomOut(); - } - } - else - { - GUI.Label(zoomOutRect, "(Out)", disabledStyle); - } - Rect zoomInfoRect = new Rect(zoomStartX, controlsStartY + slewSize, 3*slewSize, slewSize); - GUIStyle zoomInfoStyle = new GUIStyle(HighLogic.Skin.box); - zoomInfoStyle.fontSize = 12; - zoomInfoStyle.wordWrap = false; - GUI.Label(zoomInfoRect, "Zoom "+(currentFovIndex+1).ToString(), zoomInfoStyle); - - GUIStyle dataStyle = new GUIStyle(); - dataStyle.alignment = TextAnchor.MiddleCenter; - dataStyle.normal.textColor = Color.white; - - //groundStablize button - float stabilStartX = zoomStartX + zoomInRect.width + 4; - Rect stabilizeRect = new Rect(stabilStartX, controlsStartY, 3*slewSize, 3*slewSize); - if(!groundStabilized) - { - if(GUI.Button(stabilizeRect, "Lock\nTarget", HighLogic.Skin.button)) - { - GroundStabilize(); - } - } - else - { - if(GUI.Button(new Rect(stabilizeRect.x,stabilizeRect.y,stabilizeRect.width,stabilizeRect.height/2), "Unlock", HighLogic.Skin.button)) - { - ClearTarget(); - } - if(weaponManager) - { - GUIStyle gpsStyle = new GUIStyle(HighLogic.Skin.button); - gpsStyle.fontSize = 10; - if(GUI.Button(new Rect(stabilizeRect.x, stabilizeRect.y + (stabilizeRect.height / 2), stabilizeRect.width, stabilizeRect.height / 2), "Send GPS", gpsStyle)) - { - SendGPS(); - } - } - - if(!gimbalLimitReached) - { - //open square - float oSqrSize = (24f/512f) * camImageSize; - Rect oSqrRect = new Rect(imageRect.x + (camImageSize/2) - (oSqrSize/2), imageRect.y + (camImageSize/2) - (oSqrSize/2), oSqrSize, oSqrSize); - GUI.DrawTexture(oSqrRect, BDArmorySettings.Instance.openWhiteSquareTexture, ScaleMode.StretchToFill, true); - } - - //geo data - Rect geoRect = new Rect(imageRect.x, (camImageSize * 0.94f), camImageSize, 14); - string geoLabel = Misc.FormattedGeoPos(bodyRelativeGTP,false); - GUI.Label(geoRect, geoLabel, dataStyle); - - //target data - dataStyle.fontSize = 16; - float dataStartX = stabilStartX + stabilizeRect.width + 8; - Rect targetRangeRect = new Rect(imageRect.x,(camImageSize * 0.94f) - 18, camImageSize, 18); - float targetRange = Vector3.Distance(groundTargetPosition, transform.position); - string rangeString = "Range: "+targetRange.ToString("0.0")+"m"; - GUI.Label(targetRangeRect,rangeString, dataStyle); - - //laser ranging indicator - dataStyle.fontSize = 18; - string lrLabel = surfaceDetected ? "LR" : "NO LR"; - Rect lrRect = new Rect(imageRect.x, imageRect.y+(camImageSize * 0.65f), camImageSize, 20); - GUI.Label(lrRect, lrLabel, dataStyle); - - //azimuth and elevation indicator //UNFINISHED - /* - Vector2 azielPos = TargetAzimuthElevationScreenPos(imageRect, groundTargetPosition, 4); - Rect azielRect = new Rect(azielPos.x, azielPos.y, 4, 4); - GUI.DrawTexture(azielRect, BDArmorySettings.Instance.whiteSquareTexture, ScaleMode.StretchToFill, true); - */ - - //DLZ - if(weaponManager && weaponManager.selectedWeapon != null) - { - if(weaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) - { - MissileLauncher currMissile = weaponManager.currentMissile; - if(currMissile.targetingMode == MissileLauncher.TargetingModes.GPS || currMissile.targetingMode == MissileLauncher.TargetingModes.Laser) - { - MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(currMissile, Vector3.zero, groundTargetPosition); - float dlzWidth = 12 * (imageRect.width/360); - float lineWidth = 2; - Rect dlzRect = new Rect(imageRect.x + imageRect.width - (3*dlzWidth) - lineWidth, imageRect.y + (imageRect.height / 4), dlzWidth, imageRect.height / 2); - float scaleDistance = Mathf.Max(Mathf.Max(8000f, currMissile.maxStaticLaunchRange*2), targetRange); - float rangeToPixels = (1f / scaleDistance) * dlzRect.height; - - - GUI.BeginGroup(dlzRect); - - float dlzX = 0; - - BDGUIUtils.DrawRectangle(new Rect(0, 0, dlzWidth, dlzRect.height), Color.black); - - Rect maxRangeVertLineRect = new Rect(dlzRect.width - lineWidth, Mathf.Clamp(dlzRect.height - (dlz.maxLaunchRange * rangeToPixels), 0, dlzRect.height), lineWidth, Mathf.Clamp(dlz.maxLaunchRange * rangeToPixels, 0, dlzRect.height)); - BDGUIUtils.DrawRectangle(maxRangeVertLineRect, Color.white); - - - Rect maxRangeTickRect = new Rect(dlzX, maxRangeVertLineRect.y, dlzWidth, lineWidth); - BDGUIUtils.DrawRectangle(maxRangeTickRect, Color.white); - - Rect minRangeTickRect = new Rect(dlzX, Mathf.Clamp(dlzRect.height - (dlz.minLaunchRange * rangeToPixels), 0, dlzRect.height), dlzWidth, lineWidth); - BDGUIUtils.DrawRectangle(minRangeTickRect, Color.white); - - Rect rTrTickRect = new Rect(dlzX, Mathf.Clamp(dlzRect.height - (dlz.rangeTr * rangeToPixels), 0, dlzRect.height), dlzWidth, lineWidth); - BDGUIUtils.DrawRectangle(rTrTickRect, Color.white); - - Rect noEscapeLineRect = new Rect(dlzX, rTrTickRect.y, lineWidth, minRangeTickRect.y - rTrTickRect.y); - BDGUIUtils.DrawRectangle(noEscapeLineRect, Color.white); - - - GUI.EndGroup(); - - float targetDistIconSize = 6; - float targetDistY = dlzRect.y + dlzRect.height - (targetRange * rangeToPixels); - Rect targetDistanceRect = new Rect(dlzRect.x - (targetDistIconSize / 2), targetDistY, (targetDistIconSize/2) + dlzRect.width, targetDistIconSize); - BDGUIUtils.DrawRectangle(targetDistanceRect, Color.white); - } - } - - } - } - - - - - - //gimbal limit - dataStyle.fontSize = 24; - if(gimbalLimitReached) - { - Rect gLimRect = new Rect(imageRect.x, imageRect.y+(camImageSize * 0.15f), camImageSize, 28); - GUI.Label(gLimRect, "GIMBAL LIMIT", dataStyle); - } - - - //reset button - float resetStartX = stabilStartX + stabilizeRect.width + 4; - Rect resetRect = new Rect(resetStartX, controlsStartY + (2*slewSize), 3*slewSize, slewSize-1); - if(GUI.Button(resetRect, "Reset", HighLogic.Skin.button)) - { - ResetCameraButton(); - } - - - //CoM lock - Rect comLockRect = new Rect(resetRect.x, controlsStartY, 3*slewSize, slewSize-1); - GUIStyle comStyle = new GUIStyle(CoMLock ? HighLogic.Skin.box : HighLogic.Skin.button); - comStyle.fontSize = 10; - comStyle.wordWrap = false; - if(GUI.Button(comLockRect, "CoM Track",comStyle)) - { - CoMLock = !CoMLock; - } - - - //radar slave - Rect radarSlaveRect = new Rect(comLockRect.x + comLockRect.width + 4, comLockRect.y, 3*slewSize, slewSize-1); - GUIStyle radarSlaveStyle = radarLock ? HighLogic.Skin.box : HighLogic.Skin.button; - if(GUI.Button(radarSlaveRect, "Radar", radarSlaveStyle)) - { - radarLock = !radarLock; - } - - //slave turrets button - Rect slaveRect = new Rect(resetStartX, controlsStartY + slewSize, (3*slewSize), slewSize-1); - if(!slaveTurrets) - { - if(GUI.Button(slaveRect, "Turrets", HighLogic.Skin.button)) - { - SlaveTurrets (); - } - } - else - { - if(GUI.Button(slaveRect, "Turrets", HighLogic.Skin.box)) - { - UnslaveTurrets (); - } - } - - //point to gps button - Rect toGpsRect = new Rect(resetRect.x + slaveRect.width + 4, slaveRect.y, 3*slewSize, slewSize-1); - if(GUI.Button(toGpsRect, "To GPS", HighLogic.Skin.button)) - { - PointToGPSTarget(); - } - - - //nv button - float nvStartX = resetStartX + resetRect.width + 4; - Rect nvRect = new Rect(nvStartX, resetRect.y, 3*slewSize, slewSize-1); - string nvLabel = nvMode ? "NV Off" : "NV On"; - GUIStyle nvStyle = nvMode ? HighLogic.Skin.box : HighLogic.Skin.button; - if(GUI.Button(nvRect, nvLabel, nvStyle)) - { - ToggleNV(); - } - - //off button - float offStartX = nvStartX + nvRect.width + 4; - Rect offRect = new Rect(offStartX, controlsStartY, slewSize*1.5f, 3*slewSize); - if(GUI.Button(offRect, "O\nF\nF", HighLogic.Skin.button)) - { - DisableCamera(); - } - - - float indicatorSize = Mathf.Clamp(64 * (camImageSize/360), 64, 128); - float indicatorBorder = imageRect.width * 0.056f; - Vector3 vesForward = vessel.ReferenceTransform.up; - Vector3 upDirection = (transform.position-FlightGlobals.currentMainBody.transform.position).normalized; - //horizon indicator - float horizY = imageRect.y+imageRect.height-indicatorSize-indicatorBorder; - Vector3 hForward = Vector3.ProjectOnPlane(vesForward, upDirection); - float hAngle = -Misc.SignedAngle(hForward, vesForward, upDirection); - horizY -= (hAngle/90) * (indicatorSize/2); - Rect horizonRect = new Rect(indicatorBorder + imageRect.x, horizY, indicatorSize, indicatorSize); - GUI.DrawTexture(horizonRect, BDArmorySettings.Instance.horizonIndicatorTexture, ScaleMode.StretchToFill, true); - - //roll indicator - Rect rollRect = new Rect(indicatorBorder+imageRect.x, imageRect.y+imageRect.height-indicatorSize-indicatorBorder, indicatorSize, indicatorSize); - GUI.DrawTexture(rollRect, rollReferenceTexture, ScaleMode.StretchToFill, true); - Vector3 localUp = vessel.ReferenceTransform.InverseTransformDirection(upDirection); - localUp = Vector3.ProjectOnPlane(localUp, Vector3.up).normalized; - float rollAngle = -Misc.SignedAngle(-Vector3.forward, localUp, Vector3.right); - GUIUtility.RotateAroundPivot(rollAngle, rollRect.center); - GUI.DrawTexture(rollRect, rollIndicatorTexture, ScaleMode.StretchToFill, true); - GUI.matrix = Matrix4x4.identity; - - //target direction indicator - float angleToTarget = Misc.SignedAngle(hForward, Vector3.ProjectOnPlane(targetPointPosition-transform.position, upDirection), Vector3.Cross(upDirection, hForward)); - GUIUtility.RotateAroundPivot(angleToTarget, rollRect.center); - GUI.DrawTexture(rollRect, BDArmorySettings.Instance.targetDirectionTexture, ScaleMode.StretchToFill, true); - GUI.matrix = Matrix4x4.identity; - - - - - //resizing - Rect resizeRect = new Rect(camWindowRect.width-20, camWindowRect.height-20, 20, 20); - if(GUI.RepeatButton(resizeRect, "//")) - { - resizing = true; - } - - if(resizing) - { - camImageSize += Mouse.delta.x/4; - camImageSize += Mouse.delta.y/4; - - camImageSize = Mathf.Clamp(camImageSize, 360,800); - - - RefreshWindowSize(); - } - - if(Input.GetMouseButtonUp(0)) - { - resizing = false; - } - } - - void ResetCameraButton() - { - if(!resetting) - { - StartCoroutine("ResetCamera"); - } - } - - void SendGPS() - { - if(groundStabilized && weaponManager) - { - BDATargetManager.GPSTargets[BDATargetManager.BoolToTeam(weaponManager.team)].Add(new GPSTargetInfo(bodyRelativeGTP, "Target")); - } - } - - void SlaveTurrets() - { - foreach (var mtc in vessel.FindPartModulesImplementing()) - { - mtc.slaveTurrets = false; - } - - if(weaponManager && weaponManager.vesselRadarData) - { - weaponManager.vesselRadarData.slaveTurrets = false; - } - - slaveTurrets = true; - } - - void UnslaveTurrets() - { - foreach (var mtc in vessel.FindPartModulesImplementing()) - { - mtc.slaveTurrets = false; - } - - if(weaponManager && weaponManager.vesselRadarData) - { - weaponManager.vesselRadarData.slaveTurrets = false; - } - - if(weaponManager) - { - weaponManager.slavingTurrets = false; - } - } - - void UpdateSlaveData() - { - if(slaveTurrets) - { - if(weaponManager) - { - weaponManager.slavingTurrets = true; - if(groundStabilized) - { - weaponManager.slavedPosition = groundTargetPosition; - } - else - { - weaponManager.slavedPosition = targetPointPosition; - } - weaponManager.slavedVelocity = Vector3.zero; - weaponManager.slavedAcceleration = Vector3.zero; - } - } - } - - - void RefreshWindowSize() - { - float windowWidth = camImageSize+16; - float windowHeight = camImageSize+8+controlPanelHeight; - camWindowRect = new Rect(camWindowRect.x, camWindowRect.y, windowWidth, windowHeight); - } - - void SlewCamera(Vector3 direction) - { - slewedCamera = true; - StartCoroutine(SlewCamRoutine(direction)); - } - - IEnumerator SlewCamRoutine(Vector3 direction) - { - StopResetting(); - StopPointToPosRoutine(); - - radarLock = false; - float slewRate = finalSlewSpeed; - Vector3 rotationAxis = Matrix4x4.TRS(Vector3.zero, Quaternion.LookRotation(cameraParentTransform.forward, vessel.upAxis), Vector3.one).MultiplyVector(Quaternion.AngleAxis(90, Vector3.forward) * direction); - Vector3 lookVector = Quaternion.AngleAxis(slewRate * Time.deltaTime, rotationAxis) * cameraParentTransform.forward; - PointCameraModel(lookVector); - yield return new WaitForEndOfFrame(); - - - if(groundStabilized) - { - GroundStabilize(); - lookVector = groundTargetPosition - cameraParentTransform.position; - } - - PointCameraModel(lookVector); - } - - void PointToGPSTarget() - { - if(weaponManager && weaponManager.designatedGPSCoords != Vector3d.zero) - { - StartCoroutine(PointToPositionRoutine(VectorUtils.GetWorldSurfacePostion(weaponManager.designatedGPSCoords, vessel.mainBody))); - } - } - - void ZoomIn() - { - StopResetting(); - if(currentFovIndex < zoomFovs.Length-1) - { - currentFovIndex++; - } - - //fov = zoomFovs[currentFovIndex]; - } - - void ZoomOut() - { - StopResetting(); - if(currentFovIndex > 0) - { - currentFovIndex--; - } - - //fov = zoomFovs[currentFovIndex]; - } - - GameObject debugSphere; - void CreateDebugSphere() - { - debugSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); - debugSphere.GetComponent().enabled = false; - } - - void MoveDebugSphere() - { - if(!debugSphere) - { - CreateDebugSphere(); - } - debugSphere.transform.position = groundTargetPosition; - } - - void GroundStabilize() - { - if(vessel.packed) return; - StopResetting(); - - RaycastHit rayHit; - Ray ray = new Ray(cameraParentTransform.position + (50*cameraParentTransform.forward), cameraParentTransform.forward); - bool raycasted = Physics.Raycast(ray, out rayHit, maxRayDistance - 50, 557057); - if(raycasted) - { - if(FlightGlobals.getAltitudeAtPos(rayHit.point) < 0) - { - raycasted = false; - } - else - { - groundStabilized = true; - groundTargetPosition = rayHit.point; - - if(CoMLock) - { - Part p = rayHit.collider.GetComponentInParent(); - if(p && p.vessel && p.vessel.CoM != Vector3.zero) - { - groundTargetPosition = p.vessel.CoM + (p.vessel.rb_velocity * Time.fixedDeltaTime); - StartCoroutine(StabilizeNextFrame()); - } - } - Vector3d newGTP = VectorUtils.WorldPositionToGeoCoords(groundTargetPosition, vessel.mainBody); - if(newGTP != Vector3d.zero) - { - bodyRelativeGTP = newGTP; - } - } - } - - if(!raycasted) - { - Vector3 upDir = VectorUtils.GetUpDirection(cameraParentTransform.position); - double altitude = vessel.altitude; //MissileGuidance.GetRadarAltitude(vessel); - double radius = vessel.mainBody.Radius; - - Vector3d planetCenter = vessel.GetWorldPos3D() - ((vessel.altitude + vessel.mainBody.Radius) * vessel.upAxis); - double enter; - if(VectorUtils.SphereRayIntersect(ray, planetCenter, radius, out enter)) - { - if(enter > 0) - { - groundStabilized = true; - groundTargetPosition = ray.GetPoint((float)enter); - Vector3d newGTP = VectorUtils.WorldPositionToGeoCoords(groundTargetPosition, vessel.mainBody); - if(newGTP != Vector3d.zero) - { - bodyRelativeGTP = newGTP; - } - } - } - - } - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - MoveDebugSphere(); - } - } - - IEnumerator StabilizeNextFrame() - { - yield return new WaitForFixedUpdate(); - yield return new WaitForEndOfFrame(); - if(!gimbalLimitReached && surfaceDetected) - { - GroundStabilize(); - } - } - - - void GetHitPoint() - { - if(vessel.packed) return; - if(delayedEnabling) return; - - RaycastHit rayHit; - Ray ray = new Ray(cameraParentTransform.position + (50*cameraParentTransform.forward), cameraParentTransform.forward); - if(Physics.Raycast(ray, out rayHit, maxRayDistance-50, 557057)) - { - targetPointPosition = rayHit.point; - - if(!surfaceDetected && groundStabilized && !gimbalLimitReached) - { - groundStabilized = true; - groundTargetPosition = rayHit.point; - - if(CoMLock) - { - Part p = rayHit.collider.GetComponentInParent(); - if(p && p.vessel && p.vessel.Landed) - { - groundTargetPosition = p.vessel.CoM; - } - } - Vector3d newGTP = VectorUtils.WorldPositionToGeoCoords(groundTargetPosition, vessel.mainBody); - if(newGTP != Vector3d.zero) - { - bodyRelativeGTP = newGTP; - } - } - - surfaceDetected = true; - - if(groundStabilized && !gimbalLimitReached && CMDropper.smokePool!=null) - { - if(CMSmoke.RaycastSmoke(ray)) - { - surfaceDetected = false; - } - } - - } - else - { - targetPointPosition = cameraParentTransform.position + (maxRayDistance*cameraParentTransform.forward); - surfaceDetected = false; - } - } - - void ClearTarget() - { - groundStabilized = false; - } - - - IEnumerator ResetCamera() - { - resetting = true; - radarLock = false; - StopPointToPosRoutine(); - - if(groundStabilized) - { - ClearTarget(); - } - - currentFovIndex = 0; - //fov = zoomFovs[currentFovIndex]; - - while(Vector3.Angle(cameraParentTransform.forward, cameraParentTransform.parent.forward) > 0.1f) - { - Vector3 newForward = Vector3.RotateTowards(cameraParentTransform.forward, cameraParentTransform.parent.forward, 60*Mathf.Deg2Rad*Time.deltaTime, 0); - //cameraParentTransform.rotation = Quaternion.LookRotation(newForward, VectorUtils.GetUpDirection(transform.position)); - PointCameraModel(newForward); - gimbalLimitReached = false; - yield return null; - } - resetting = false; - } - - void StopPointToPosRoutine() - { - if(slewingToPosition) - { - StartCoroutine(StopPTPRRoutine()); - } - } - - IEnumerator StopPTPRRoutine() - { - stopPTPR = true; - yield return null; - yield return new WaitForEndOfFrame(); - stopPTPR = false; - } - - bool stopPTPR = false; - bool slewingToPosition = false; - public IEnumerator PointToPositionRoutine(Vector3 position) - { - yield return StopPTPRRoutine(); - stopPTPR = false; - slewingToPosition = true; - radarLock = false; - StopResetting(); - ClearTarget(); - while(!stopPTPR && Vector3.Angle(cameraParentTransform.transform.forward, position - (cameraParentTransform.transform.position)) > 0.1f) - { - Vector3 newForward = Vector3.RotateTowards(cameraParentTransform.transform.forward, position - cameraParentTransform.transform.position, 90 * Mathf.Deg2Rad * Time.fixedDeltaTime, 0); - //cameraParentTransform.rotation = Quaternion.LookRotation(newForward, VectorUtils.GetUpDirection(transform.position)); - PointCameraModel(newForward); - yield return new WaitForFixedUpdate(); - if(gimbalLimitReached) - { - ClearTarget(); - StartCoroutine("ResetCamera"); - slewingToPosition = false; - yield break; - } - } - if(surfaceDetected && !stopPTPR) - { - //cameraParentTransform.transform.rotation = Quaternion.LookRotation(position - cameraParentTransform.position, VectorUtils.GetUpDirection(transform.position)); - PointCameraModel(position-cameraParentTransform.position); - GroundStabilize(); - } - slewingToPosition = false; - yield break; - } - - void StopResetting() - { - if(resetting) - { - StopCoroutine("ResetCamera"); - resetting = false; - } - } - - void ParseFovs() - { - /* - string[] fovStrings = zoomFOVs.Split(new char[]{','}); - zoomFovs = new float[fovStrings.Length]; - for(int i = 0; i < fovStrings.Length; i++) - { - zoomFovs[i] = float.Parse(fovStrings[i]); - }*/ - - zoomFovs = Misc.ParseToFloatArray(zoomFOVs); - } - - void OnDestroy() - { - if(HighLogic.LoadedSceneIsFlight) - { - windowIsOpen = false; - if(wpmr) - { - if(slaveTurrets) - { - weaponManager.slavingTurrets = false; - } - } - } - } - - Vector2 TargetAzimuthElevationScreenPos(Rect screenRect, Vector3 targetPosition, float textureSize) - { - Vector3 localPos = vessel.ReferenceTransform.InverseTransformPoint(targetPosition); - Vector3 aziRef = Vector3.up; - Vector3 aziPos = Vector3.ProjectOnPlane(localPos, Vector3.forward); - float elevation = VectorUtils.SignedAngle(aziPos, localPos, Vector3.forward); - float normElevation = elevation / 70; - - - float azimuth = VectorUtils.SignedAngle(aziRef, aziPos, Vector3.right); - float normAzimuth = Mathf.Clamp(azimuth / 120, -1, 1); - - float x = screenRect.x + (screenRect.width/2) + (normAzimuth * (screenRect.width / 2)) - (textureSize/2); - float y = screenRect.y + (screenRect.height/4) + (normElevation * (screenRect.height / 4)) - (textureSize/2); - - x = Mathf.Clamp(x, textureSize / 2, screenRect.width - (textureSize / 2)); - y = Mathf.Clamp(y, textureSize / 2, (screenRect.height) - (textureSize / 2)); - - return new Vector2(x, y); - } - - - - - } -} - diff --git a/BahaTurret/ModuleTurret.cs b/BahaTurret/ModuleTurret.cs deleted file mode 100644 index 2046d7bcc..000000000 --- a/BahaTurret/ModuleTurret.cs +++ /dev/null @@ -1,364 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; -namespace BahaTurret -{ - public class ModuleTurret : PartModule - { - - [KSPField] - public int turretID = 0; - - - [KSPField] - public string pitchTransformName = "pitchTransform"; - public Transform pitchTransform; - - [KSPField] - public string yawTransformName = "yawTransform"; - public Transform yawTransform; - - - Transform referenceTransform; //set this to gun's fireTransform - - [KSPField] - public float pitchSpeedDPS; - [KSPField] - public float yawSpeedDPS; - - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Max Pitch"), - UI_FloatRange(minValue = 0f, maxValue = 60f, stepIncrement = 1f, scene = UI_Scene.All)] - public float maxPitch; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Min Pitch"), - UI_FloatRange(minValue = 1f, maxValue = 0f, stepIncrement = 1f, scene = UI_Scene.All)] - public float minPitch; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Yaw Range"), - UI_FloatRange(minValue = 1f, maxValue = 60f, stepIncrement = 1f, scene = UI_Scene.All)] - public float yawRange; - - [KSPField(isPersistant = true)] - public float minPitchLimit = 400; - [KSPField(isPersistant = true)] - public float maxPitchLimit = 400; - [KSPField(isPersistant = true)] - public float yawRangeLimit = 400; - - [KSPField] - public bool smoothRotation = false; - [KSPField] - public float smoothMultiplier = 10; - - float pitchTargetOffset; - float yawTargetOffset; - - //sfx - [KSPField] - public string audioPath; - [KSPField] - public float maxAudioPitch = 0.5f; - [KSPField] - public float minAudioPitch = 0f; - [KSPField] - public float maxVolume = 1; - [KSPField] - public float minVolume = 0; - - AudioClip soundClip; - AudioSource audioSource; - bool hasAudio = false; - float audioRotationRate = 0; - float targetAudioRotationRate = 0; - Vector3 lastTurretDirection; - float maxAudioRotRate; - - - public override void OnStart (StartState state) - { - base.OnStart (state); - - SetupTweakables(); - - - pitchTransform = part.FindModelTransform(pitchTransformName); - yawTransform = part.FindModelTransform (yawTransformName); - - if(!pitchTransform) - { - Debug.LogWarning(part.partInfo.title + " has no pitchTransform"); - } - - if(!yawTransform) - { - Debug.LogWarning(part.partInfo.title + " has no yawTransform"); - } - - if(!referenceTransform) - { - SetReferenceTransform(pitchTransform); - } - - if(!string.IsNullOrEmpty(audioPath) && (yawSpeedDPS!=0 || pitchSpeedDPS!=0)) - { - soundClip = GameDatabase.Instance.GetAudioClip(audioPath); - - audioSource = gameObject.AddComponent(); - audioSource.clip = soundClip; - audioSource.loop = true; - audioSource.dopplerLevel = 0; - audioSource.minDistance = .5f; - audioSource.maxDistance = 150; - audioSource.Play(); - audioSource.volume = 0; - audioSource.pitch = 0; - audioSource.priority = 9999; - audioSource.spatialBlend = 1; - - lastTurretDirection = yawTransform.parent.InverseTransformDirection(pitchTransform.forward); - - maxAudioRotRate = Mathf.Min(yawSpeedDPS, pitchSpeedDPS); - - hasAudio = true; - } - } - - void FixedUpdate() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(hasAudio) - { - audioRotationRate = Mathf.Lerp(audioRotationRate, targetAudioRotationRate, 20*Time.fixedDeltaTime); - audioRotationRate = Mathf.Clamp01(audioRotationRate); - - - if(audioRotationRate < 0.05f) - { - audioSource.volume = 0; - } - else - { - audioSource.volume = Mathf.Clamp(2f * audioRotationRate, minVolume * BDArmorySettings.BDARMORY_WEAPONS_VOLUME, maxVolume * BDArmorySettings.BDARMORY_WEAPONS_VOLUME); - audioSource.pitch = Mathf.Clamp(audioRotationRate, minAudioPitch, maxAudioPitch); - } - - - - Vector3 tDir = yawTransform.parent.InverseTransformDirection(pitchTransform.forward); - float angle = Vector3.Angle(tDir, lastTurretDirection); - float rate = Mathf.Clamp01((angle / Time.fixedDeltaTime)/maxAudioRotRate); - lastTurretDirection = tDir; - - targetAudioRotationRate = rate; - } - } - } - - void Update() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(hasAudio) - { - if(!BDArmorySettings.GameIsPaused && audioRotationRate > 0.05f) - { - if(!audioSource.isPlaying) audioSource.Play(); - } - else - { - if(audioSource.isPlaying) - { - audioSource.Stop(); - } - } - } - } - } - - - public void AimToTarget(Vector3 targetPosition, bool pitch = true, bool yaw = true) - { - if(!yawTransform) - { - return; - } - - float deltaTime = Time.fixedDeltaTime; - - Vector3 localTargetYaw = yawTransform.parent.InverseTransformPoint(targetPosition - (yawTargetOffset * pitchTransform.right)); - Vector3 targetYaw = Vector3.ProjectOnPlane(localTargetYaw, Vector3.up); - float targetYawAngle = VectorUtils.SignedAngle(Vector3.forward, targetYaw, Vector3.right); - targetYawAngle = Mathf.Clamp(targetYawAngle, -yawRange / 2, yawRange / 2); - - Quaternion currYawRot = yawTransform.localRotation; - yawTransform.localRotation = Quaternion.Euler(0, targetYawAngle, 0); - Vector3 localTargetPitch = pitchTransform.parent.InverseTransformPoint(targetPosition - (pitchTargetOffset * pitchTransform.up)); - yawTransform.localRotation = currYawRot; - localTargetPitch.z = Mathf.Abs(localTargetPitch.z);//prevents from aiming wonky if target is behind - Vector3 targetPitch = Vector3.ProjectOnPlane(localTargetPitch, Vector3.right); - float targetPitchAngle = VectorUtils.SignedAngle(Vector3.forward, targetPitch, Vector3.up); - targetPitchAngle = Mathf.Clamp(targetPitchAngle, minPitch, maxPitch); - - float yawOffset = Vector3.Angle(yawTransform.parent.InverseTransformDirection(yawTransform.forward), targetYaw); - float currentYawSign = Mathf.Sign(Vector3.Dot(yawTransform.localRotation*Vector3.forward, Vector3.right)); - float pitchOffset = Vector3.Angle(pitchTransform.parent.InverseTransformDirection(pitchTransform.forward), targetPitch); - - float linPitchMult = yawOffset > 0 ? Mathf.Clamp01((pitchOffset / yawOffset) * (yawSpeedDPS/pitchSpeedDPS)) : 1; - float linYawMult = pitchOffset > 0 ? Mathf.Clamp01((yawOffset / pitchOffset) * (pitchSpeedDPS/yawSpeedDPS)) : 1; - - float yawSpeed; - float pitchSpeed; - if(smoothRotation) - { - yawSpeed = Mathf.Clamp(yawOffset * smoothMultiplier, 1f, yawSpeedDPS) * deltaTime; - pitchSpeed = Mathf.Clamp(pitchOffset * smoothMultiplier, 1f, pitchSpeedDPS) * deltaTime; - } - else - { - yawSpeed = yawSpeedDPS * deltaTime; - pitchSpeed = pitchSpeedDPS * deltaTime; - } - - yawSpeed *= linYawMult; - pitchSpeed *= linPitchMult; - - if(yawRange < 360 && Mathf.Abs(targetYawAngle) > 90 && currentYawSign != Mathf.Sign(targetYawAngle)) - { - targetYawAngle = 5 * Mathf.Sign(targetYawAngle); - } - - if(yaw) yawTransform.localRotation = Quaternion.RotateTowards(yawTransform.localRotation, Quaternion.Euler(0, targetYawAngle, 0), yawSpeed); - if(pitch) pitchTransform.localRotation = Quaternion.RotateTowards(pitchTransform.localRotation, Quaternion.Euler(-targetPitchAngle, 0, 0), pitchSpeed); - } - - public bool ReturnTurret() - { - if(!yawTransform) - { - return false; - } - - float deltaTime = Time.fixedDeltaTime; - - float yawOffset = Vector3.Angle(yawTransform.forward, yawTransform.parent.forward); - float pitchOffset = Vector3.Angle(pitchTransform.forward, yawTransform.forward); - - float yawSpeed; - float pitchSpeed; - - if(smoothRotation) - { - yawSpeed = Mathf.Clamp(yawOffset * smoothMultiplier, 1f, yawSpeedDPS) * deltaTime; - pitchSpeed = Mathf.Clamp(pitchOffset * smoothMultiplier, 1f, pitchSpeedDPS) * deltaTime; - } - else - { - yawSpeed = yawSpeedDPS * deltaTime; - pitchSpeed = pitchSpeedDPS * deltaTime; - } - - float linPitchMult = yawOffset > 0 ? Mathf.Clamp01((pitchOffset / yawOffset) * (yawSpeedDPS/pitchSpeedDPS)) : 1; - float linYawMult = pitchOffset > 0 ? Mathf.Clamp01((yawOffset / pitchOffset) * (pitchSpeedDPS/yawSpeedDPS)) : 1; - - yawSpeed *= linYawMult; - pitchSpeed *= linPitchMult; - - yawTransform.localRotation = Quaternion.RotateTowards(yawTransform.localRotation, Quaternion.identity, yawSpeed); - pitchTransform.localRotation = Quaternion.RotateTowards(pitchTransform.localRotation, Quaternion.identity, pitchSpeed); - - if(yawTransform.localRotation == Quaternion.identity && pitchTransform.localRotation == Quaternion.identity) - { - return true; - } - else - { - return false; - } - } - - - public bool TargetInRange(Vector3 targetPosition, float thresholdDegrees, float maxDistance) - { - if(!pitchTransform) - { - return false; - } - bool withinView = Vector3.Angle(targetPosition-pitchTransform.position, pitchTransform.forward) < thresholdDegrees; - bool withinDistance = (targetPosition-pitchTransform.position).magnitude < maxDistance; - return (withinView && withinDistance); - } - - public void SetReferenceTransform(Transform t) - { - referenceTransform = t; - pitchTargetOffset = pitchTransform.InverseTransformPoint(referenceTransform.position).y; - yawTargetOffset = yawTransform.InverseTransformPoint(referenceTransform.position).x; - } - - void SetupTweakables() - { - var minPitchRange = (UI_FloatRange) Fields["minPitch"].uiControlEditor; - if(minPitchLimit > 90) - { - minPitchLimit = minPitch; - } - if(minPitchLimit == 0) - { - Fields["minPitch"].guiActiveEditor = false; - } - minPitchRange.minValue = minPitchLimit; - minPitchRange.maxValue = 0; - - var maxPitchRange = (UI_FloatRange) Fields["maxPitch"].uiControlEditor; - if(maxPitchLimit > 90) - { - maxPitchLimit = maxPitch; - } - if(maxPitchLimit == 0) - { - Fields["maxPitch"].guiActiveEditor = false; - } - maxPitchRange.maxValue = maxPitchLimit; - maxPitchRange.minValue = 0; - - var yawRangeEd = (UI_FloatRange) Fields["yawRange"].uiControlEditor; - if(yawRangeLimit > 360) - { - yawRangeLimit = yawRange; - } - - if(yawRangeLimit == 0) - { - Fields["yawRange"].guiActiveEditor = false; - /* - onlyFireInRange = false; - Fields["onlyFireInRange"].guiActiveEditor = false; - */ - } - else if(yawRangeLimit < 0) - { - yawRangeEd.minValue = 0; - yawRangeEd.maxValue = 360; - - if(yawRange < 0) yawRange = 360; - } - else - { - yawRangeEd.minValue = 0; - yawRangeEd.maxValue = yawRangeLimit; - } - - } - } -} - diff --git a/BahaTurret/ModuleWeapon.cs b/BahaTurret/ModuleWeapon.cs deleted file mode 100644 index 7d7ee8818..000000000 --- a/BahaTurret/ModuleWeapon.cs +++ /dev/null @@ -1,1979 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using KSP.UI.Screens; -namespace BahaTurret -{ - public class ModuleWeapon : PartModule, IBDWeapon - { - public static ObjectPool bulletPool; - public static ObjectPool shellPool; - - public enum WeaponTypes{Ballistic, Cannon, Laser} - public enum WeaponStates{Enabled, Disabled, PoweringUp, PoweringDown} - public enum BulletDragTypes { None, AnalyticEstimate, NumericalIntegration } - public WeaponStates weaponState = WeaponStates.Disabled; - - //name - [KSPField] - public string shortName = string.Empty; - - //transforms - [KSPField] - public string fireTransformName = "fireTransform"; - public Transform[] fireTransforms; - - [KSPField] - public string shellEjectTransformName = "shellEject"; - public Transform[] shellEjectTransforms; - - - //animations - private float fireAnimSpeed = 1; //is set when setting up animation so it plays a full animation for each shot (animation speed depends on rate of fire) - [KSPField] - public bool hasDeployAnim = false; - [KSPField] - public string deployAnimName = "deployAnim"; - AnimationState deployState; - [KSPField] - public bool hasFireAnimation = false; - [KSPField] - public string fireAnimName = "fireAnim"; - private AnimationState fireState; - [KSPField] - public bool spinDownAnimation = false; - private bool spinningDown = false; - - - //weapon specifications - [KSPField] - public float maxTargetingRange = 2000; //max range for raycasting and sighting - [KSPField] - public float roundsPerMinute = 850; //rate of fire - [KSPField] - public float maxDeviation = 1; //max inaccuracy deviation in degrees - [KSPField] - public float maxEffectiveDistance = 2500; //used by AI to select appropriate weapon - [KSPField] - public float bulletMass = 5.40133e-5f; //mass in tons - used for damage and recoil and drag - [KSPField] - public float bulletVelocity = 860; //velocity in meters/second - - [KSPField] - public string bulletDragTypeName = "AnalyticEstimate"; - public BulletDragTypes bulletDragType; - [KSPField] - public float bulletDragArea = 1.209675e-5f; //drag area of the bullet in m^2; equal to Cd * A with A being the frontal area of the bullet; as a first approximation, take Cd to be 0.3 - public float bulletBallisticCoefficient; //bullet mass / bullet drag area. Used in analytic estimate to speed up code - - [KSPField] - public string ammoName = "50CalAmmo"; //resource usage TODO: multi resource requirement - [KSPField] - public float requestResourceAmount = 1; //amount of resource/ammo to deplete per shot - [KSPField] - public float shellScale = 0.66f; //scale of shell to eject - [KSPField] - public bool hasRecoil = true; - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Fire Limits"), - UI_Toggle(disabledText = "None", enabledText = "In range")] - public bool onlyFireInRange = true; //prevent firing when gun's turret is trying to exceed gimbal limits - [KSPField] - public bool bulletDrop = true; //projectiles are affected by gravity - [KSPField] - public string weaponType = "ballistic"; //ballistic(normal bullets), cannon(explosive bullets), or laser - public WeaponTypes eWeaponType; - [KSPField] - public float laserDamage = 10000; //base damage/second of lasers - - //cannon shell specfications - [KSPField] - public float cannonShellRadius = 30; //max radius of explosion forces/damage - [KSPField] - public float cannonShellPower = 8; //explosion's impulse force - [KSPField] - public float cannonShellHeat = -1; //if non-negative, heat damage - - //projectile graphics - [KSPField] - public string projectileColor = "255, 130, 0, 255"; //final color of projectile - Color projectileColorC; - [KSPField] - public bool fadeColor = false; - [KSPField] - public string startColor = "255, 160, 0, 200"; //if fade color is true, projectile starts at this color - Color startColorC; - [KSPField] - public float tracerStartWidth = 0.25f; - [KSPField] - public float tracerEndWidth = 0.2f; - [KSPField] - public float tracerLength = 0; //if set to zero, tracer will be the length of the distance covered by the projectile in one physics timestep - [KSPField] - public float tracerDeltaFactor = 2.65f; - [KSPField] - public float nonTracerWidth = 0.01f; - [KSPField] - public int tracerInterval = 0; - [KSPField] - public float tracerLuminance = 1.75f; - int tracerIntervalCounter = 0; - [KSPField] - public string bulletTexturePath = "BDArmory/Textures/bullet"; - - [KSPField] - public bool oneShotWorldParticles = false; - - - //heat - [KSPField] - public float maxHeat = 3600; - [KSPField] - public float heatPerShot = 75; - [KSPField] - public float heatLoss = 250; - public float heat = 0; - public bool isOverheated = false; - - //canon explosion effects - [KSPField] - public string explModelPath = "BDArmory/Models/explosion/explosion"; - - [KSPField] - public string explSoundPath = "BDArmory/Sounds/explode1"; - // - - - //Used for scaling laser damage down based on distance. - [KSPField] - public float tanAngle = 0.0001f; - //Angle of divergeance/2. Theoretical minimum value calculated using θ = (1.22 L/RL)/2, - //where L is laser's wavelength and RL is the radius of the mirror (=gun). - - - //audioclip paths - [KSPField] - public string fireSoundPath = "BDArmory/Parts/50CalTurret/sounds/shot"; - [KSPField] - public string overheatSoundPath = "BDArmory/Parts/50CalTurret/sounds/turretOverheat"; - [KSPField] - public string chargeSoundPath = "BDArmory/Parts/laserTest/sounds/charge"; - - //audio - [KSPField] - public bool oneShotSound = true; //play audioclip on every shot, instead of playing looping audio while firing - [KSPField] - public float soundRepeatTime = 1; //looped audio will loop back to this time (used for not playing the opening bit, eg the ramp up in pitch of gatling guns) - [KSPField] - public string reloadAudioPath = string.Empty; - AudioClip reloadAudioClip; - [KSPField] - public string reloadCompletePath = string.Empty; - private bool wasFiring = false; //used for knowing when to stop looped audio clip (when you're not shooting, but you were) - AudioClip reloadCompleteAudioClip; - AudioClip fireSound; - AudioClip overheatSound; - AudioClip chargeSound; - AudioSource audioSource; - AudioSource audioSource2; - - //AI - public bool aiControlled = false; - public bool autoFire = false; - public float autoFireLength = 0; - public float autoFireTimer = 0; - //used by AI to lead moving targets - private float targetDistance = 0; - private Vector3 targetPosition; - private Vector3 targetVelocity; - private Vector3 targetAcceleration; - Vector3 finalAimTarget; - Vector3 lastFinalAimTarget; - public Vessel legacyTargetVessel; - bool targetAcquired = false; - - //used to reduce volume of audio if multiple guns are being fired (needs to be improved/changed) - //private int numberOfGuns = 0; - - //UI gauges(next to staging icon) - private ProtoStageIconInfo heatGauge = null; - private ProtoStageIconInfo reloadBar = null; - [KSPField] - public bool showReloadMeter = false; //used for cannons or guns with extremely low rate of fire - - //AI will fire gun if target is within this Cos(angle) of barrel - public float maxAutoFireCosAngle = 0.9993908f; //corresponds to ~2 degrees - - //aimer textures - Vector3 pointingAtPosition; - Vector3 bulletPrediction; - Vector3 fixedLeadOffset = Vector3.zero; - float targetLeadDistance = 0; - - - //SPECAL FEATURES - - //Air Detonating Rounds - [KSPField] - public bool airDetonation = false; - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Default Detonation Range"), - UI_FloatRange(minValue = 500, maxValue = 3500f, stepIncrement = 1f, scene = UI_Scene.All)] - public float defaultDetonationRange = 3500; - [KSPField] - public float maxAirDetonationRange = 3500; - float detonationRange = 2000; - [KSPField] - public bool airDetonationTiming = true; - - //auto proximity tracking - [KSPField] - public float autoProxyTrackRange = 0; - bool atprAcquired = false; - int aptrTicker = 0; - - //gapless particles - List gaplessEmitters = new List(); - - //muzzleflash emitters - List muzzleFlashEmitters; - - - //module references - [KSPField] - public int turretID = 0; - public ModuleTurret turret; - MissileFire mf = null; - public MissileFire weaponManager - { - get - { - if (!mf) - { - foreach (var wm in vessel.FindPartModulesImplementing()) - { - mf = wm; - break; - } - } - return mf; - } - } - - LineRenderer[] laserRenderers; - - // - float timeFired = 0; - public float initialFireDelay = 0; //used to ripple fire multiple weapons of this type - - [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Barrage")] - public bool useRippleFire = true; - [KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "Toggle Barrage")] - public void ToggleRipple() - { - foreach(var craftPart in EditorLogic.fetch.ship.parts) - { - if(craftPart.name == part.name) - { - foreach(var weapon in craftPart.FindModulesImplementing()) - { - weapon.useRippleFire = !weapon.useRippleFire; - } - } - } - } - - bool pointingAtSelf = false; //true if weapon is pointing at own vessel - bool userFiring = false; - Vector3 laserPoint; - public bool slaved = false; - - public Transform turretBaseTransform - { - get - { - if(turret) - { - return turret.yawTransform.parent; - } - else - { - return fireTransforms[0]; - } - } - } - - public float maxPitch - { - get - { - return turret ? turret.maxPitch : 0; - } - } - - public float minPitch - { - get - { - return turret ? turret.minPitch : 0; - } - } - - public float yawRange - { - get - { - return turret ? turret.yawRange : 0; - } - } - - //weapon interface - public WeaponClasses GetWeaponClass() - { - return WeaponClasses.Gun; - } - - public string GetShortName() - { - return shortName; - } - - public Part GetPart() - { - return part; - } - - public string GetSubLabel() - { - return string.Empty; - } - - [KSPAction("Toggle Weapon")] - public void AGToggle(KSPActionParam param) - { - Toggle(); - } - - [KSPField(guiActive = true, guiActiveEditor = false, guiName = "Status")] - public string guiStatusString = "Disabled"; - - //PartWindow buttons - [KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "Toggle")] - public void Toggle() - { - if(weaponState == WeaponStates.Disabled || weaponState == WeaponStates.PoweringDown) - { - EnableWeapon(); - } - else - { - DisableWeapon(); - } - } - - bool agHoldFiring = false; - - [KSPAction("Fire (Toggle)")] - public void AGFireToggle(KSPActionParam param) - { - agHoldFiring = (param.type == KSPActionType.Activate); - } - - [KSPAction("Fire (Hold)")] - public void AGFireHold(KSPActionParam param) - { - StartCoroutine(FireHoldRoutine(param.group)); - } - - IEnumerator FireHoldRoutine(KSPActionGroup group) - { - KeyBinding key = Misc.AGEnumToKeybinding(group); - if(key == null) - { - yield break; - } - - while(key.GetKey()) - { - agHoldFiring = true; - yield return null; - } - - agHoldFiring = false; - yield break; - } - - - - - public override void OnStart (StartState state) - { - base.OnStart (state); - - ParseWeaponType(); - ParseBulletDragType(); - - bulletBallisticCoefficient = bulletMass / bulletDragArea * 1000; //1000 to convert from tonnes to kilograms - - if(shortName == string.Empty) - { - shortName = part.partInfo.title; - } - - foreach(var emitter in part.FindModelComponents()) - { - emitter.emit = false; - } - - if(roundsPerMinute >= 1500) - { - Events["ToggleRipple"].guiActiveEditor = false; - Fields["useRippleFire"].guiActiveEditor = false; - } - - if(airDetonation) - { - var detRange = (UI_FloatRange)Fields["defaultDetonationRange"].uiControlEditor; - detRange.maxValue = maxAirDetonationRange; - } - else - { - Fields["defaultDetonationRange"].guiActive = false; - Fields["defaultDetonationRange"].guiActiveEditor = false; - } - - muzzleFlashEmitters = new List(); - foreach(Transform mtf in part.FindModelTransforms("muzzleTransform")) - { - KSPParticleEmitter kpe = mtf.GetComponent(); - muzzleFlashEmitters.Add(kpe); - kpe.emit = false; - } - - if(HighLogic.LoadedSceneIsFlight) - { - if(eWeaponType != WeaponTypes.Laser) - { - if(bulletPool == null) - { - SetupBulletPool(); - } - if(shellPool == null) - { - SetupShellPool(); - } - } - - //setup transforms - fireTransforms = part.FindModelTransforms(fireTransformName); - shellEjectTransforms = part.FindModelTransforms(shellEjectTransformName); - - //setup emitters - foreach(var pe in part.FindModelComponents()) - { - pe.maxSize *= part.rescaleFactor; - pe.minSize *= part.rescaleFactor; - pe.shape3D *= part.rescaleFactor; - pe.shape2D *= part.rescaleFactor; - pe.shape1D *= part.rescaleFactor; - - if(pe.useWorldSpace && !oneShotWorldParticles) - { - BDAGaplessParticleEmitter gpe = pe.gameObject.AddComponent(); - gpe.part = part; - gaplessEmitters.Add(gpe); - } - } - - - //setup projectile colors - projectileColorC = Misc.ParseColor255(projectileColor); - startColorC = Misc.ParseColor255(startColor); - - //init and zero points - targetPosition = Vector3.zero; - pointingAtPosition = Vector3.zero; - bulletPrediction = Vector3.zero; - - //setup audio - SetupAudio(); - - //laser setup - if(eWeaponType == WeaponTypes.Laser) - { - SetupLaserSpecifics(); - } - } - else if(HighLogic.LoadedSceneIsEditor) - { - fireTransforms = part.FindModelTransforms(fireTransformName); - } - - //turret setup - foreach(var turr in part.FindModulesImplementing()) - { - if(turr.turretID == turretID) - { - turret = turr; - turret.SetReferenceTransform(fireTransforms[0]); - break; - } - } - - if(!turret) - { - Fields["onlyFireInRange"].guiActive = false; - Fields["onlyFireInRange"].guiActiveEditor = false; - } - - - //setup animations - if(hasDeployAnim) - { - deployState = Misc.SetUpSingleAnimation(deployAnimName, this.part); - deployState.normalizedTime = 0; - deployState.speed = 0; - deployState.enabled = true; - } - if(hasFireAnimation) - { - fireState = Misc.SetUpSingleAnimation (fireAnimName, this.part); - fireState.enabled = false; - } - - BDArmorySettings.OnVolumeChange += UpdateVolume; - } - - void UpdateVolume() - { - if(audioSource) - { - audioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - } - if(audioSource2) - { - audioSource2.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - } - if(lowpassFilter) - { - lowpassFilter.cutoffFrequency = BDArmorySettings.IVA_LOWPASS_FREQ; - } - } - - void OnDestroy() - { - BDArmorySettings.OnVolumeChange -= UpdateVolume; - } - - public int rippleIndex = 0; - void Update() - { - if(HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && vessel.IsControllable) - { - - if(lowpassFilter) - { - if(InternalCamera.Instance && InternalCamera.Instance.isActive) - { - lowpassFilter.enabled = true; - } - else - { - lowpassFilter.enabled = false; - } - } - - if(weaponState == WeaponStates.Enabled && (TimeWarp.WarpMode != TimeWarp.Modes.HIGH || TimeWarp.CurrentRate == 1)) - { - userFiring = (BDInputUtils.GetKey(BDInputSettingsFields.WEAP_FIRE_KEY) && (vessel.isActiveVessel || BDArmorySettings.REMOTE_SHOOTING) && !MapView.MapIsEnabled && !aiControlled); - if((userFiring || autoFire || agHoldFiring) && (yawRange == 0 || (maxPitch - minPitch) == 0 || turret.TargetInRange(finalAimTarget, 10, float.MaxValue))) - { - if(useRippleFire && (pointingAtSelf || isOverheated)) - { - StartCoroutine(IncrementRippleIndex(0)); - finalFire = false; - } - else if(eWeaponType == WeaponTypes.Ballistic || eWeaponType == WeaponTypes.Cannon) - { - finalFire = true; - } - } - else - { - if(spinDownAnimation) spinningDown = true; - if(eWeaponType == WeaponTypes.Laser) audioSource.Stop(); - if(!oneShotSound && wasFiring) - { - audioSource.Stop(); - wasFiring = false; - audioSource2.PlayOneShot(overheatSound); - } - } - } - else - { - audioSource.Stop(); - autoFire = false; - } - - if(spinningDown && spinDownAnimation && hasFireAnimation) - { - if(fireState.normalizedTime > 1) fireState.normalizedTime = 0; - fireState.speed = fireAnimSpeed; - fireAnimSpeed = Mathf.Lerp(fireAnimSpeed, 0, 0.04f); - } - } - } - - IEnumerator AimAndFireAtEndOfFrame() - { - RunTrajectorySimulation(); - Aim(); - CheckWeaponSafety(); - - if(eWeaponType != WeaponTypes.Laser) yield return new WaitForEndOfFrame(); - if(finalFire) - { - - if(eWeaponType == WeaponTypes.Laser) - { - if(FireLaser()) - { - for(int i = 0; i < laserRenderers.Length; i++) - { - laserRenderers[i].enabled = true; - } - } - else - { - for(int i = 0; i < laserRenderers.Length; i++) - { - laserRenderers[i].enabled = false; - } - audioSource.Stop (); - } - } - else - { - if (useRippleFire && weaponManager.gunRippleIndex != rippleIndex) - { - //timeFired = Time.time + (initialFireDelay - (60f / roundsPerMinute)) * TimeWarp.CurrentRate; - finalFire = false; - } - else - { - finalFire = true; - } - - if(finalFire) - Fire(); - } - - finalFire = false; - } - - yield break; - } - - bool finalFire = false; - public bool recentlyFiring //used by guard to know if it should evaid this - { - get - { - return Time.time - timeFired < 1; - } - } - - void FixedUpdate() - { - if(HighLogic.LoadedSceneIsFlight && !vessel.packed) - { - if(!vessel.IsControllable) - { - if(weaponState != WeaponStates.PoweringDown || weaponState != WeaponStates.Disabled) - { - DisableWeapon(); - } - return; - } - - if(showReloadMeter) - { - //UpdateReloadMeter(); - } - else - { - //UpdateHeatMeter(); - } - UpdateHeat(); - - - if(weaponState == WeaponStates.Enabled && (TimeWarp.WarpMode!=TimeWarp.Modes.HIGH || TimeWarp.CurrentRate == 1)) - { - UpdateTargetVessel(); - //Aim(); - StartCoroutine(AimAndFireAtEndOfFrame()); - - - - if(eWeaponType == WeaponTypes.Laser) - { - if((userFiring || autoFire || agHoldFiring) && (!turret || turret.TargetInRange(targetPosition, 10, float.MaxValue))) - { - finalFire = true; - } - else - { - for(int i = 0; i < laserRenderers.Length; i++) - { - laserRenderers[i].enabled = false; - } - audioSource.Stop (); - } - } - } - else if(eWeaponType == WeaponTypes.Laser) - { - for(int i = 0; i < laserRenderers.Length; i++) - { - laserRenderers[i].enabled = false; - } - audioSource.Stop (); - } - - - //autofiring with AI - if(targetAcquired && aiControlled) - { - Transform fireTransform = fireTransforms[0]; - Vector3 targetRelPos = (finalAimTarget)-fireTransform.position; - Vector3 aimDirection = fireTransform.forward; - float targetCosAngle = Vector3.Dot(aimDirection, targetRelPos.normalized); - - Vector3 targetDiffVec = finalAimTarget - lastFinalAimTarget; - Vector3 projectedTargetPos = targetDiffVec; - //projectedTargetPos /= TimeWarp.fixedDeltaTime; - //projectedTargetPos *= TimeWarp.fixedDeltaTime; - projectedTargetPos *= 2; //project where the target will be in 2 timesteps - projectedTargetPos += finalAimTarget; - - targetDiffVec.Normalize(); - Vector3 lastTargetRelPos = (lastFinalAimTarget) - fireTransform.position; - - if (BDATargetManager.CheckSafeToFireGuns(weaponManager, aimDirection, 1000, 0.999848f) && //~1 degree of unsafe angle - (targetCosAngle >= maxAutoFireCosAngle || //check if directly on target - (Vector3.Dot(targetDiffVec, targetRelPos) * Vector3.Dot(targetDiffVec, lastTargetRelPos) < 0 && targetCosAngle > 0))) //check if target will pass this point soon - { - autoFire = true; - } - else - { - autoFire = false; - } - } - else - { - autoFire = false; - } - - //disable autofire after burst length - if(autoFire && Time.time-autoFireTimer > autoFireLength) - { - autoFire = false; - legacyTargetVessel = null; - } - } - lastFinalAimTarget = finalAimTarget; - } - - - - //Aiming used if part has a turret module - void Aim() - { - //AI control - if(aiControlled && !slaved) - { - if(legacyTargetVessel) - { - targetPosition += legacyTargetVessel.rb_velocity * Time.fixedDeltaTime; - } - else if(!targetAcquired) - { - autoFire = false; - return; - } - } - - - - if(!slaved && !aiControlled && (yawRange > 0 || maxPitch-minPitch > 0)) - { - //MouseControl - Vector3 mouseAim = new Vector3(Input.mousePosition.x/Screen.width, Input.mousePosition.y/Screen.height, 0); - Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mouseAim); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, maxTargetingRange, 557057)) - { - targetPosition = hit.point; - - //aim through self vessel if occluding mouseray - Part p = hit.collider.gameObject.GetComponentInParent(); - if(p && p.vessel && p.vessel == vessel) - { - targetPosition = ray.direction * maxTargetingRange + FlightCamera.fetch.mainCamera.transform.position; - } - } - else - { - targetPosition = (ray.direction * (maxTargetingRange+(FlightCamera.fetch.Distance*0.75f))) + FlightCamera.fetch.mainCamera.transform.position; - if(legacyTargetVessel!=null && legacyTargetVessel.loaded) - { - targetPosition = ray.direction * Vector3.Distance(legacyTargetVessel.transform.position, FlightCamera.fetch.mainCamera.transform.position) + FlightCamera.fetch.mainCamera.transform.position; - } - } - } - - - //aim assist - Vector3 finalTarget = targetPosition; - Vector3 originalTarget = targetPosition; - targetDistance = Vector3.Distance(finalTarget, transform.position); - targetLeadDistance = targetDistance; - if((BDArmorySettings.AIM_ASSIST || aiControlled) && eWeaponType!=WeaponTypes.Laser) - { - float gAccel = (float) FlightGlobals.getGeeForceAtPosition(finalTarget).magnitude; - float time = targetDistance/(bulletVelocity); - - if(targetAcquired) - { - float time2 = VectorUtils.CalculateLeadTime(finalTarget-fireTransforms[0].position, targetVelocity-vessel.srf_velocity, bulletVelocity); - if(time2 > 0) time = time2; - finalTarget += (targetVelocity-vessel.srf_velocity) * time; //target vessel relative velocity compensation - - Vector3 acceleration = targetAcceleration; - finalTarget += (0.5f * acceleration * time * time); //target acceleration - } - else if(vessel.altitude < 6000) - { - float time2 = VectorUtils.CalculateLeadTime(finalTarget-fireTransforms[0].position, -part.rb.velocity, bulletVelocity); - if(time2 > 0) time = time2; - finalTarget += (-part.rb.velocity*(time+Time.fixedDeltaTime)); //this vessel velocity compensation against stationary - } - Vector3 up = (finalTarget - vessel.mainBody.transform.position).normalized; - if(bulletDrop && vessel.srfSpeed < 750) finalTarget += (0.5f*gAccel*time*time*up); //gravity compensation - - targetLeadDistance = Vector3.Distance(finalTarget, fireTransforms[0].position); - - fixedLeadOffset = originalTarget-finalTarget; //for aiming fixed guns to moving target - - - //airdetonation - if(airDetonation) - { - if(targetAcquired && airDetonationTiming) - { - detonationRange = Mathf.Clamp(targetLeadDistance, 500, maxAirDetonationRange) - 25f; - } - else - { - detonationRange = defaultDetonationRange; - } - } - - } - - if(airDetonation) - { - detonationRange *= UnityEngine.Random.Range(0.97f, 1.03f); - } - - finalAimTarget = finalTarget; - - //final turret aiming - if(slaved && !targetAcquired) return; - if(turret) - { - bool origSmooth = turret.smoothRotation; - if(aiControlled || slaved) - { - turret.smoothRotation = false; - } - turret.AimToTarget(finalTarget); - turret.smoothRotation = origSmooth; - } - } - - private void Fire() - { - if(BDArmorySettings.GameIsPaused) - { - if(audioSource.isPlaying) - { - audioSource.Stop(); - } - return; - } - - float timeGap = (60/roundsPerMinute) * TimeWarp.CurrentRate; - if(Time.time-timeFired > timeGap && !isOverheated && !pointingAtSelf && !Misc.CheckMouseIsOnGui() && WMgrAuthorized()) - { - bool effectsShot = false; - //Transform[] fireTransforms = part.FindModelTransforms("fireTransform"); - for(int i = 0; i < fireTransforms.Length; i++) - { - if((BDArmorySettings.INFINITE_AMMO || part.RequestResource(ammoName, requestResourceAmount)>0)) - { - Transform fireTransform = fireTransforms[i]; - spinningDown = false; - - //recoil - if(hasRecoil) - { - part.rb.AddForceAtPosition((-fireTransform.forward) * (bulletVelocity*bulletMass), fireTransform.position, ForceMode.Impulse); - } - - if(!effectsShot) - { - //sound - if(oneShotSound) - { - audioSource.Stop(); - audioSource.PlayOneShot(fireSound); - } - else - { - wasFiring = true; - if(!audioSource.isPlaying) - { - audioSource.clip = fireSound; - audioSource.loop = false; - audioSource.time = 0; - audioSource.Play(); - } - else - { - if (audioSource.time >= fireSound.length) - { - audioSource.time = soundRepeatTime; - } - } - } - - //animation - if(hasFireAnimation) - { - float unclampedSpeed = (roundsPerMinute*fireState.length)/60f; - float lowFramerateFix = 1; - if(roundsPerMinute > 500f) - { - lowFramerateFix = (0.02f/Time.deltaTime); - } - fireAnimSpeed = Mathf.Clamp (unclampedSpeed, 1f * lowFramerateFix, 20f * lowFramerateFix); - fireState.enabled = true; - if(unclampedSpeed == fireAnimSpeed || fireState.normalizedTime > 1) - { - fireState.normalizedTime = 0; - } - fireState.speed = fireAnimSpeed; - fireState.normalizedTime = Mathf.Repeat(fireState.normalizedTime, 1); - - //Debug.Log("fireAnim time: " + fireState.normalizedTime + ", speed; " + fireState.speed); - } - - //muzzle flash - - foreach(var pEmitter in muzzleFlashEmitters) - { - //KSPParticleEmitter pEmitter = mtf.gameObject.GetComponent(); - if(!pEmitter.useWorldSpace || oneShotWorldParticles) - { - if(pEmitter.maxEnergy < 0.5f) - { - float twoFrameTime = Mathf.Clamp(Time.deltaTime * 2f, 0.02f, 0.499f); - pEmitter.maxEnergy = twoFrameTime; - pEmitter.minEnergy = twoFrameTime/3f; - } - pEmitter.Emit(); - } - } - - foreach(var gpe in gaplessEmitters) - { - gpe.EmitParticles(); - } - - //shell ejection - if(BDArmorySettings.EJECT_SHELLS) - { - for(int e = 0; e < shellEjectTransforms.Length; e++) - { - Transform sTf = shellEjectTransforms[e]; - //GameObject ejectedShell = (GameObject) Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/shell/model"), sTf.position + (part.rb.velocity*Time.fixedDeltaTime), sTf.rotation); - GameObject ejectedShell = shellPool.GetPooledObject(); - ejectedShell.transform.position = sTf.position;//+(part.rb.velocity*TimeWarp.fixedDeltaTime); - ejectedShell.transform.rotation = sTf.rotation; - ejectedShell.transform.localScale = Vector3.one * shellScale; - ShellCasing shellComponent = ejectedShell.GetComponent(); - shellComponent.initialV = part.rb.velocity; - ejectedShell.SetActive(true); - } - } - effectsShot = true; - } - - - //firing bullet - GameObject firedBullet = bulletPool.GetPooledObject(); - PooledBullet pBullet = firedBullet.GetComponent(); - firedBullet.transform.position = fireTransform.position; - - pBullet.mass = bulletMass; - pBullet.ballisticCoefficient = bulletBallisticCoefficient; - pBullet.flightTimeElapsed = 0; - - timeFired = Time.time; - - //Vector3 firedVelocity = fireTransform.rotation * new Vector3(randomZ,randomY,bulletVelocity).normalized * bulletVelocity; - Vector3 firedVelocity = VectorUtils.WeightedDirectionDeviation(fireTransform.forward, maxDeviation) * bulletVelocity; - - - //firedBullet.transform.position -= firedVelocity * Time.fixedDeltaTime; - firedBullet.transform.position += part.rb.velocity * Time.fixedDeltaTime; - pBullet.currentVelocity = part.rb.velocity + firedVelocity; - - pBullet.initialSpeed = bulletVelocity; - pBullet.sourceVessel = this.vessel; - pBullet.bulletTexturePath = bulletTexturePath; - pBullet.projectileColor = projectileColorC; - pBullet.startColor = startColorC; - pBullet.fadeColor = fadeColor; - - tracerIntervalCounter++; - if(tracerIntervalCounter > tracerInterval) - { - tracerIntervalCounter = 0; - pBullet.tracerStartWidth = tracerStartWidth; - pBullet.tracerEndWidth = tracerEndWidth; - } - else - { - pBullet.tracerStartWidth = nonTracerWidth; - pBullet.tracerEndWidth = nonTracerWidth; - pBullet.startColor.a *= 0.5f; - pBullet.projectileColor.a *= 0.5f; - } - - pBullet.tracerLength = tracerLength; - pBullet.tracerDeltaFactor = tracerDeltaFactor; - pBullet.tracerLuminance = tracerLuminance; - - pBullet.bulletDrop = bulletDrop; - - if(eWeaponType == WeaponTypes.Cannon) - { - pBullet.bulletType = PooledBullet.PooledBulletTypes.Explosive; - pBullet.explModelPath = explModelPath; - pBullet.explSoundPath = explSoundPath; - pBullet.blastPower = cannonShellPower; - pBullet.blastHeat = cannonShellHeat; - pBullet.radius = cannonShellRadius; - pBullet.airDetonation = airDetonation; - pBullet.detonationRange = detonationRange; - } - else - { - pBullet.bulletType = PooledBullet.PooledBulletTypes.Standard; - pBullet.airDetonation = false; - } - switch(bulletDragType) - { - case BulletDragTypes.None: - pBullet.dragType = PooledBullet.BulletDragTypes.None; - break; - case BulletDragTypes.AnalyticEstimate: - pBullet.dragType = PooledBullet.BulletDragTypes.AnalyticEstimate; - break; - case BulletDragTypes.NumericalIntegration: - pBullet.dragType = PooledBullet.BulletDragTypes.NumericalIntegration; - break; - } - - pBullet.gameObject.SetActive(true); - - - //heat - heat += heatPerShot; - } - else - { - spinningDown = true; - if(!oneShotSound && wasFiring) - { - audioSource.Stop (); - wasFiring = false; - audioSource2.PlayOneShot(overheatSound); - } - } - } - - if(useRippleFire) - { - StartCoroutine(IncrementRippleIndex(initialFireDelay * TimeWarp.CurrentRate)); - } - } - else - { - spinningDown = true; - } - } - - IEnumerator IncrementRippleIndex(float delay) - { - if(delay > 0) - { - yield return new WaitForSeconds(delay); - } - weaponManager.gunRippleIndex = weaponManager.gunRippleIndex +1; - - //Debug.Log("incrementing ripple index to: " + weaponManager.gunRippleIndex); - } - - - private bool FireLaser() - { - float maxDistance = BDArmorySettings.PHYSICS_RANGE; - if(BDArmorySettings.PHYSICS_RANGE == 0) maxDistance = 2500; - - float chargeAmount = requestResourceAmount * TimeWarp.fixedDeltaTime; - if(!pointingAtSelf && !Misc.CheckMouseIsOnGui() && WMgrAuthorized() && !isOverheated && (part.RequestResource(ammoName, chargeAmount)>=chargeAmount || BDArmorySettings.INFINITE_AMMO)) - { - if(!audioSource.isPlaying) - { - audioSource.PlayOneShot (chargeSound); - audioSource.Play(); - audioSource.loop = true; - - } - for(int i = 0; i < fireTransforms.Length; i++) - { - Transform tf = fireTransforms[i]; - - LineRenderer lr = laserRenderers[i]; - //lr.SetPosition(0, tf.position + (part.rb.velocity*Time.fixedDeltaTime)); - - Vector3 rayDirection = tf.forward; - - Vector3 targetDirection = Vector3.zero; //autoTrack enhancer - Vector3 targetDirectionLR = tf.forward; - Vector3 physStepFix = Vector3.zero; - - - if(legacyTargetVessel!=null && legacyTargetVessel.loaded) - { - physStepFix = legacyTargetVessel.rb_velocity*Time.fixedDeltaTime; - targetDirection = (legacyTargetVessel.CoM+physStepFix) - tf.position; - - - if(Vector3.Angle(rayDirection, targetDirection) < 1) - { - rayDirection = targetDirection; - targetDirectionLR = legacyTargetVessel.CoM+(2*physStepFix) - tf.position; - } - } - else if(slaved) - { - //physStepFix = (targetVelocity)*Time.fixedDeltaTime; - physStepFix = Vector3.zero; - targetDirection = (targetPosition+physStepFix) - tf.position; - - - rayDirection = targetDirection; - targetDirectionLR = targetDirection + physStepFix; - } - - - - Ray ray = new Ray(tf.position, rayDirection); - lr.useWorldSpace = false; - lr.SetPosition(0, Vector3.zero); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, maxDistance, 557057)) - { - lr.useWorldSpace = true; - laserPoint = hit.point + physStepFix; - - //lr.SetPosition(1, lr.transform.InverseTransformPoint(laserPoint)); - lr.SetPosition(0, tf.position+(part.rb.velocity*Time.fixedDeltaTime)); - lr.SetPosition(1, laserPoint); - - - if(Time.time-timeFired > 6/120 && BDArmorySettings.BULLET_HITS) - { - BulletHitFX.CreateBulletHit(hit.point, hit.normal, false); - } - - Part p = hit.collider.gameObject.GetComponentInParent(); - if(p && p.vessel && p.vessel!=this.vessel) - { - float distance = hit.distance; - //Scales down the damage based on the increased surface area of the area being hit by the laser. Think flashlight on a wall. - p.temperature += laserDamage/(1+Mathf.PI*Mathf.Pow(tanAngle*distance,2))*TimeWarp.fixedDeltaTime; - - if(BDArmorySettings.INSTAKILL) p.temperature += p.maxTemp; - } - } - else - { - laserPoint = lr.transform.InverseTransformPoint((targetDirectionLR*maxDistance)+tf.position); - lr.SetPosition(1, laserPoint); - } - } - heat += heatPerShot * TimeWarp.CurrentRate; - return true; - } - else - { - return false; - } - } - - - - bool WMgrAuthorized() - { - MissileFire manager = BDArmorySettings.Instance.ActiveWeaponManager; - if(manager != null && manager.vessel == vessel) - { - if(manager.hasSingleFired) return false; - else return true; - } - else - { - return true; - } - } - - void CheckWeaponSafety() - { - pointingAtSelf = false; - for(int i = 0; i < fireTransforms.Length; i++) - { - Ray ray = new Ray(fireTransforms[i].position, fireTransforms[i].forward); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, maxTargetingRange, 557057)) - { - Part p = hit.collider.gameObject.GetComponentInParent(); - if(p && p.vessel && p.vessel == vessel) - { - pointingAtSelf = true; - break; - } - } - else - { - pointingAtSelf = false; - } - - - if(targetAcquired) - { - pointingAtPosition = fireTransforms[i].transform.position + (ray.direction * targetLeadDistance); - } - else - { - pointingAtPosition = fireTransforms[i].position + (ray.direction * (maxTargetingRange)); - } - } - - - } - - void RunTrajectorySimulation() - { - //trajectory simulation - if(BDArmorySettings.AIM_ASSIST && BDArmorySettings.DRAW_AIMERS) - { - Transform fireTransform = fireTransforms[0]; - - if(eWeaponType == WeaponTypes.Laser) - { - Ray ray = new Ray(fireTransform.position, fireTransform.forward); - RaycastHit rayHit; - if(Physics.Raycast(ray, out rayHit, maxTargetingRange, 557057)) - { - bulletPrediction = rayHit.point; - } - else - { - bulletPrediction = ray.GetPoint(maxTargetingRange); - } - - pointingAtPosition = ray.GetPoint(maxTargetingRange); - } - else //ballistic/cannon weapons - { - float simDeltaTime = 0.15f; - - - Vector3 simVelocity = part.rb.velocity+(bulletVelocity*fireTransform.forward); - Vector3 simCurrPos = fireTransform.position + (part.rb.velocity*Time.fixedDeltaTime); - Vector3 simPrevPos = simCurrPos; - Vector3 simStartPos = simCurrPos; - bool simulating = true; - - List pointPositions = new List(); - pointPositions.Add(simCurrPos); - - while(simulating) - { - - RaycastHit hit; - if(bulletDrop) simVelocity += FlightGlobals.getGeeForceAtPosition(simCurrPos) * simDeltaTime; - simCurrPos += simVelocity * simDeltaTime; - pointPositions.Add(simCurrPos); - if(Physics.Raycast(simPrevPos,simCurrPos-simPrevPos, out hit, Vector3.Distance(simPrevPos,simCurrPos), 557057)) - { - Vessel hitVessel = null; - try - { - hitVessel = Part.FromGO(hit.rigidbody.gameObject).vessel; - } - catch(NullReferenceException){} - - if(hitVessel==null || (hitVessel!=null && hitVessel != vessel)) - { - bulletPrediction = hit.point; - simulating = false; - } - - } - - - simPrevPos = simCurrPos; - - if(legacyTargetVessel!=null && legacyTargetVessel.loaded && !legacyTargetVessel.Landed && Vector3.Distance(simStartPos,simCurrPos) > targetLeadDistance) - { - bulletPrediction = simStartPos + (simCurrPos-simStartPos).normalized*targetLeadDistance; - simulating = false; - } - - if((simStartPos-simCurrPos).magnitude> maxTargetingRange) - { - - bulletPrediction = simStartPos + ((simCurrPos-simStartPos).normalized*maxTargetingRange); - simulating = false; - } - } - - - if(BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) - { - Vector3[] pointsArray = pointPositions.ToArray(); - if(gameObject.GetComponent()==null) - { - LineRenderer lr = gameObject.AddComponent(); - lr.SetWidth(.1f, .1f); - lr.SetVertexCount(pointsArray.Length); - for(int i = 0; i(); - lr.enabled = true; - lr.SetVertexCount(pointsArray.Length); - for(int i = 0; i()!=null) - { - gameObject.GetComponent().enabled = false; - } - */ - } - - } - - } - } - - Coroutine startupRoutine; - Coroutine shutdownRoutine; - - public void EnableWeapon() - { - if(weaponState == WeaponStates.Enabled || weaponState == WeaponStates.PoweringUp) - { - return; - } - - StopShutdownStartupRoutines(); - - startupRoutine = StartCoroutine(StartupRoutine()); - } - - void StopShutdownStartupRoutines() - { - if(shutdownRoutine != null) - { - StopCoroutine(shutdownRoutine); - shutdownRoutine = null; - } - - if(startupRoutine != null) - { - StopCoroutine(startupRoutine); - startupRoutine = null; - } - } - - IEnumerator StartupRoutine() - { - weaponState = WeaponStates.PoweringUp; - UpdateGUIWeaponState(); - - if(hasDeployAnim && deployState) - { - deployState.enabled = true; - deployState.speed = 1; - while(deployState.normalizedTime < 1)//wait for animation here - { - yield return null; - } - deployState.normalizedTime = 1; - deployState.speed = 0; - deployState.enabled = false; - } - - weaponState = WeaponStates.Enabled; - UpdateGUIWeaponState(); - BDArmorySettings.Instance.UpdateCursorState(); - } - - void UpdateGUIWeaponState() - { - guiStatusString = weaponState.ToString(); - } - - public void DisableWeapon() - { - if(weaponState == WeaponStates.Disabled || weaponState == WeaponStates.PoweringDown) - { - return; - } - - StopShutdownStartupRoutines(); - - shutdownRoutine = StartCoroutine(ShutdownRoutine()); - } - - IEnumerator ShutdownRoutine() - { - weaponState = WeaponStates.PoweringDown; - UpdateGUIWeaponState(); - BDArmorySettings.Instance.UpdateCursorState(); - if(turret) - { - yield return new WaitForSeconds(0.2f); - - while(!turret.ReturnTurret()) //wait till turret has returned - { - yield return new WaitForFixedUpdate(); - } - } - - if(hasDeployAnim) - { - deployState.enabled = true; - deployState.speed = -1; - while(deployState.normalizedTime > 0) - { - yield return null; - } - deployState.normalizedTime = 0; - deployState.speed = 0; - deployState.enabled = false; - } - - weaponState = WeaponStates.Disabled; - UpdateGUIWeaponState(); - } - - void UpdateHeat() - { - heat = Mathf.Clamp(heat - heatLoss * TimeWarp.fixedDeltaTime, 0, Mathf.Infinity); - if(heat>maxHeat && !isOverheated) - { - isOverheated = true; - autoFire = false; - audioSource.Stop (); - wasFiring = false; - audioSource2.PlayOneShot(overheatSound); - weaponManager.ResetGuardInterval(); - } - if(heat < maxHeat/3 && isOverheated) //reset on cooldown - { - isOverheated = false; - heat = 0; - } - } - - void UpdateHeatMeter() - { - //heat - if(heat > maxHeat/3) - { - if(heatGauge == null) - { - heatGauge = InitHeatGauge(); - } - heatGauge.SetValue(heat, maxHeat/3, maxHeat); - } - else if(heatGauge != null && heat < maxHeat/4) - { - part.stackIcon.ClearInfoBoxes(); - heatGauge = null; - } - } - - void UpdateReloadMeter() - { - if(Time.time-timeFired < (60/roundsPerMinute) && Time.time-timeFired > 0.1f) - { - if(reloadBar == null) - { - reloadBar = InitReloadBar(); - if(reloadAudioClip) - { - audioSource.PlayOneShot(reloadAudioClip); - } - } - reloadBar.SetValue(Time.time-timeFired, 0, 60/roundsPerMinute); - } - else if(reloadBar != null) - { - part.stackIcon.ClearInfoBoxes(); - reloadBar = null; - if(reloadCompleteAudioClip) - { - audioSource.PlayOneShot(reloadCompleteAudioClip); - } - - } - } - - AudioLowPassFilter lowpassFilter; - void SetupAudio() - { - fireSound = GameDatabase.Instance.GetAudioClip(fireSoundPath); - overheatSound = GameDatabase.Instance.GetAudioClip(overheatSoundPath); - if(!audioSource) - { - audioSource = gameObject.AddComponent(); - audioSource.bypassListenerEffects = true; - audioSource.minDistance = .3f; - audioSource.maxDistance = 1000; - audioSource.priority = 10; - audioSource.dopplerLevel = 0; - audioSource.spatialBlend = 1; - } - - if(!audioSource2) - { - audioSource2 = gameObject.AddComponent(); - audioSource2.bypassListenerEffects = true; - audioSource2.minDistance = .3f; - audioSource2.maxDistance = 1000; - audioSource2.dopplerLevel = 0; - audioSource2.priority = 10; - audioSource2.spatialBlend = 1; - } - - if(reloadAudioPath != string.Empty) - { - reloadAudioClip = (AudioClip) GameDatabase.Instance.GetAudioClip(reloadAudioPath); - } - if(reloadCompletePath != string.Empty) - { - reloadCompleteAudioClip = (AudioClip) GameDatabase.Instance.GetAudioClip(reloadCompletePath); - } - - if(!lowpassFilter) - { - lowpassFilter = gameObject.AddComponent(); - lowpassFilter.cutoffFrequency = BDArmorySettings.IVA_LOWPASS_FREQ; - lowpassFilter.lowpassResonanceQ = 1f; - } - - UpdateVolume(); - } - - void SetupLaserSpecifics() - { - chargeSound = GameDatabase.Instance.GetAudioClip(chargeSoundPath); - if(HighLogic.LoadedSceneIsFlight) - { - audioSource.clip = fireSound; - } - - laserRenderers = new LineRenderer[fireTransforms.Length]; - - for(int i = 0; i < fireTransforms.Length; i++) - { - Transform tf = fireTransforms[i]; - laserRenderers[i] = tf.gameObject.AddComponent(); - Color laserColor = Misc.ParseColor255(projectileColor); - laserColor.a = laserColor.a/2; - laserRenderers[i].material = new Material(Shader.Find ("KSP/Particles/Alpha Blended")); - laserRenderers[i].material.SetColor("_TintColor", laserColor); - laserRenderers[i].material.mainTexture = GameDatabase.Instance.GetTexture("BDArmory/Textures/laser", false); - laserRenderers[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;//= false; - laserRenderers[i].receiveShadows = false; - laserRenderers[i].SetWidth(tracerStartWidth, tracerEndWidth); - laserRenderers[i].SetVertexCount(2); - laserRenderers[i].SetPosition(0, Vector3.zero); - laserRenderers[i].SetPosition(1, Vector3.zero); - laserRenderers[i].useWorldSpace = false; - laserRenderers[i].enabled = false; - - } - } - - void ParseWeaponType() - { - weaponType = weaponType.ToLower(); - - switch (weaponType) - { - case "ballistic": - eWeaponType = WeaponTypes.Ballistic; - break; - - case "cannon": - eWeaponType = WeaponTypes.Cannon; - break; - - case "laser": - eWeaponType = WeaponTypes.Laser; - break; - } - } - - void ParseBulletDragType() - { - bulletDragTypeName = bulletDragTypeName.ToLower(); - - switch (bulletDragTypeName) - { - case "none": - bulletDragType = BulletDragTypes.None; - break; - - case "numericalintegration": - bulletDragType = BulletDragTypes.NumericalIntegration; - break; - - case "analyticestimate": - bulletDragType = BulletDragTypes.AnalyticEstimate; - break; - } - } - - private ProtoStageIconInfo InitReloadBar() - { - ProtoStageIconInfo v = part.stackIcon.DisplayInfo(); - - v.SetMsgBgColor(XKCDColors.DarkGrey); - v.SetMsgTextColor(XKCDColors.White); - v.SetMessage("Reloading"); - v.SetProgressBarBgColor(XKCDColors.DarkGrey); - v.SetProgressBarColor(XKCDColors.Silver); - - return v; - } - - private ProtoStageIconInfo InitHeatGauge() //thanks DYJ - { - ProtoStageIconInfo v = part.stackIcon.DisplayInfo(); - - v.SetMsgBgColor(XKCDColors.DarkRed); - v.SetMsgTextColor(XKCDColors.Orange); - v.SetMessage("Overheat"); - v.SetProgressBarBgColor(XKCDColors.DarkRed); - v.SetProgressBarColor(XKCDColors.Orange); - - return v; - } - - void SetupBulletPool() - { - GameObject templateBullet = new GameObject("Bullet"); - templateBullet.SetActive(false); - templateBullet.AddComponent(); - - - bulletPool = ObjectPool.CreateObjectPool(templateBullet, 100, true, true); - } - - void SetupShellPool() - { - GameObject templateShell = (GameObject) Instantiate(GameDatabase.Instance.GetModel("BDArmory/Models/shell/model")); - templateShell.SetActive(false); - templateShell.AddComponent(); - - shellPool = ObjectPool.CreateObjectPool(templateShell, 50, true, true); - } - - public Vector3 GetLeadOffset() - { - return fixedLeadOffset; - } - - void UpdateTargetVessel() - { - targetAcquired = false; - slaved = false; - bool atprWasAcquired = atprAcquired; - atprAcquired = false; - - //targetVessel = null; - if(BDArmorySettings.ALLOW_LEGACY_TARGETING) - { - if(!aiControlled) - { - if(vessel.targetObject != null && vessel.targetObject.GetVessel() != null) - { - legacyTargetVessel = vessel.targetObject.GetVessel(); - } - } - } - - if(weaponManager) - { - - //legacy or visual range guard targeting - if(aiControlled && weaponManager && legacyTargetVessel && (BDArmorySettings.ALLOW_LEGACY_TARGETING || (legacyTargetVessel.transform.position - transform.position).magnitude < weaponManager.guardRange)) - { - targetPosition = legacyTargetVessel.CoM; - targetVelocity = legacyTargetVessel.srf_velocity; - targetAcceleration = legacyTargetVessel.acceleration; - targetPosition += targetVelocity * Time.fixedDeltaTime; - targetAcquired = true; - return; - } - - if(weaponManager.slavingTurrets && turret) - { - slaved = true; - targetPosition = weaponManager.slavedPosition + (3*weaponManager.slavedVelocity*Time.fixedDeltaTime); - targetVelocity = weaponManager.slavedVelocity; - targetAcceleration = weaponManager.slavedAcceleration; - targetAcquired = true; - return; - } - - if(weaponManager.vesselRadarData && weaponManager.vesselRadarData.locked) - { - TargetSignatureData targetData = weaponManager.vesselRadarData.lockedTargetData.targetData; - targetVelocity = targetData.velocity; - targetPosition = targetData.predictedPosition + (3*targetVelocity*Time.fixedDeltaTime); - if(targetData.vessel) - { - targetVelocity = targetData.vessel.srf_velocity; - targetPosition = targetData.vessel.CoM + (targetData.vessel.rb_velocity*Time.fixedDeltaTime); - } - targetAcceleration = targetData.acceleration; - targetAcquired = true; - return; - } - - //auto proxy tracking - if(vessel.isActiveVessel && autoProxyTrackRange > 0) - { - if(aptrTicker < 20) - { - aptrTicker++; - - if(atprWasAcquired) - { - targetVelocity += targetAcceleration * Time.fixedDeltaTime; - targetPosition += targetVelocity * Time.fixedDeltaTime; - targetAcquired = true; - atprAcquired = true; - } - } - else - { - aptrTicker = 0; - Vessel tgt = null; - float closestSqrDist = autoProxyTrackRange * autoProxyTrackRange; - foreach(var v in BDATargetManager.LoadedVessels) - { - if(!v || !v.loaded) continue; - if(!v.IsControllable) continue; - if(v == vessel) continue; - Vector3 targetVector = v.transform.position - part.transform.position; - if(Vector3.Dot(targetVector, fireTransforms[0].forward) < 0) continue; - float sqrDist = (v.transform.position - part.transform.position).sqrMagnitude; - if(sqrDist > closestSqrDist) continue; - if(Vector3.Angle(targetVector, fireTransforms[0].forward) > 20) continue; - tgt = v; - closestSqrDist = sqrDist; - } - - if(tgt != null) - { - targetAcquired = true; - atprAcquired = true; - targetPosition = tgt.CoM; - targetVelocity = tgt.srf_velocity; - targetAcceleration = tgt.acceleration; - } - } - } - } - - } - - - - void OnGUI() - { - if(weaponState == WeaponStates.Enabled && vessel && !vessel.packed && vessel.isActiveVessel && BDArmorySettings.DRAW_AIMERS && !aiControlled & !MapView.MapIsEnabled && !pointingAtSelf) - { - float size = 30; - - Vector3 reticlePosition; - if(BDArmorySettings.AIM_ASSIST && vessel.srfSpeed < Krakensbane.Threshold) - { - if(targetAcquired && (slaved || yawRange < 1 || maxPitch-minPitch < 1)) - { - reticlePosition = pointingAtPosition+fixedLeadOffset; - - if(!slaved) - { - BDGUIUtils.DrawLineBetweenWorldPositions(pointingAtPosition, reticlePosition, 2, new Color(0, 1, 0, 0.6f)); - } - - BDGUIUtils.DrawTextureOnWorldPos(pointingAtPosition, BDArmorySettings.Instance.greenDotTexture, new Vector2(6, 6), 0); - - if(atprAcquired) - { - BDGUIUtils.DrawTextureOnWorldPos(targetPosition, BDArmorySettings.Instance.openGreenSquare, new Vector2(20, 20), 0); - } - } - else - { - reticlePosition = bulletPrediction; - } - } - else - { - reticlePosition = pointingAtPosition; - } - - - - Texture2D texture; - if(Vector3.Angle(pointingAtPosition-transform.position, finalAimTarget-transform.position) < 1f) - { - texture = BDArmorySettings.Instance.greenSpikedPointCircleTexture; - } - else - { - texture = BDArmorySettings.Instance.greenPointCircleTexture; - } - BDGUIUtils.DrawTextureOnWorldPos (reticlePosition, texture, new Vector2 (size, size), 0); - - if(BDArmorySettings.DRAW_DEBUG_LINES) - { - if(targetAcquired) - { - BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position, targetPosition, 2, Color.blue); - } - } - } - - if(HighLogic.LoadedSceneIsEditor && BDArmorySettings.showWeaponAlignment) - { - DrawAlignmentIndicator(); - } - } - - void DrawAlignmentIndicator() - { - if(fireTransforms == null || fireTransforms[0] == null) return; - - Transform refTransform = EditorLogic.RootPart.GetReferenceTransform(); - - if(!refTransform) return; - - Vector3 fwdPos = fireTransforms[0].position + (5 * fireTransforms[0].forward); - BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position, fwdPos, 4, Color.green); - - Vector3 referenceDirection = refTransform.up; - Vector3 refUp = -refTransform.forward; - Vector3 refRight = refTransform.right; - - Vector3 refFwdPos = fireTransforms[0].position + (5 * referenceDirection); - BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position, refFwdPos, 2, Color.white); - - BDGUIUtils.DrawLineBetweenWorldPositions(fwdPos, refFwdPos, 2, XKCDColors.Orange); - - Vector2 guiPos; - if(BDGUIUtils.WorldToGUIPos(fwdPos, out guiPos)) - { - Rect angleRect = new Rect(guiPos.x, guiPos.y, 100, 200); - - Vector3 pitchVector = (5 *Vector3.ProjectOnPlane(fireTransforms[0].forward, refRight)); - Vector3 yawVector = (5 * Vector3.ProjectOnPlane(fireTransforms[0].forward, refUp)); - - BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position + pitchVector, fwdPos, 3, Color.white); - BDGUIUtils.DrawLineBetweenWorldPositions(fireTransforms[0].position + yawVector, fwdPos, 3, Color.white); - - float pitch = Vector3.Angle(pitchVector, referenceDirection); - float yaw = Vector3.Angle(yawVector, referenceDirection); - - string convergeDistance; - - Vector3 projAxis = Vector3.Project(refTransform.position - fireTransforms[0].transform.position, refRight); - float xDist = projAxis.magnitude; - float convergeAngle = 90 - Vector3.Angle(yawVector, refTransform.up); - if(Vector3.Dot(fireTransforms[0].forward, projAxis) > 0) - { - convergeDistance = "Converge: "+Mathf.Round((xDist * Mathf.Tan(convergeAngle*Mathf.Deg2Rad))).ToString()+"m"; - } - else - { - convergeDistance = "Diverging"; - } - - string xAngle = "X: " + Vector3.Angle(fireTransforms[0].forward, pitchVector).ToString("0.00"); - string yAngle = "Y: " + Vector3.Angle(fireTransforms[0].forward, yawVector).ToString("0.00"); - - GUI.Label(angleRect, xAngle+"\n"+ yAngle + "\n"+convergeDistance); - } - } - - - - } -} - diff --git a/BahaTurret/ModuleWingCommander.cs b/BahaTurret/ModuleWingCommander.cs deleted file mode 100644 index 43d103e96..000000000 --- a/BahaTurret/ModuleWingCommander.cs +++ /dev/null @@ -1,599 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class ModuleWingCommander : PartModule - { - - public MissileFire weaponManager; - - List friendlies; - - List wingmen; - [KSPField(isPersistant = true)] - public string savedWingmen = string.Empty; - - [KSPField(guiActive = false, guiActiveEditor = true, guiName = "")] - public string guiTitle = "WingCommander:"; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Spread"), - UI_FloatRange(minValue = 20f, maxValue = 200f, stepIncrement = 1, scene = UI_Scene.Editor)] - public float spread = 50; - - [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Lag"), - UI_FloatRange(minValue = 0f, maxValue = 100f, stepIncrement = 1, scene = UI_Scene.Editor)] - public float lag = 10; - - [KSPField(isPersistant = true)] - public bool commandSelf = false; - - List commandedPositions; - bool drawMouseDiamond = false; - - ScreenMessage screenMessage; - - - //int focusIndex = 0; - List focusIndexes; - - [KSPEvent(guiActive = true, guiName = "ToggleGUI")] - public void ToggleGUI() - { - showGUI = !showGUI; - if(showGUI) - { - RefreshFriendlies(); - - //TEMPORARY - wingmen = new List(); - foreach(var p in friendlies) - { - wingmen.Add(p); - } - } - } - - - public override void OnStart(StartState state) - { - base.OnStart(state); - - if(HighLogic.LoadedSceneIsFlight) - { - focusIndexes = new List(); - commandedPositions = new List(); - part.force_activate(); - - StartCoroutine(StartupRoutine()); - - GameEvents.onGameStateSave.Add(SaveWingmen); - GameEvents.onVesselLoaded.Add(OnVesselLoad); - GameEvents.onVesselDestroy.Add(OnVesselLoad); - GameEvents.onVesselGoOnRails.Add(OnVesselLoad); - MissileFire.OnToggleTeam += OnToggleTeam; - - screenMessage = new ScreenMessage("", 2, ScreenMessageStyle.LOWER_CENTER); - } - } - - void OnToggleTeam(MissileFire mf, BDArmorySettings.BDATeams team) - { - RefreshFriendlies(); - RefreshWingmen(); - } - - IEnumerator StartupRoutine() - { - while(vessel.packed) - { - yield return null; - } - - weaponManager = part.FindModuleImplementing(); - - RefreshFriendlies(); - RefreshWingmen(); - LoadWingmen(); - } - - void OnDestroy() - { - if(HighLogic.LoadedSceneIsFlight) - { - GameEvents.onGameStateSave.Remove(SaveWingmen); - GameEvents.onVesselLoaded.Remove(OnVesselLoad); - GameEvents.onVesselDestroy.Remove(OnVesselLoad); - GameEvents.onVesselGoOnRails.Remove(OnVesselLoad); - MissileFire.OnToggleTeam -= OnToggleTeam; - } - - } - - void OnVesselLoad(Vessel v) - { - if(HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed) - { - RefreshFriendlies(); - RefreshWingmen(); - } - } - - void RefreshFriendlies() - { - if(!weaponManager) return; - friendlies = new List(); - - foreach(var v in BDATargetManager.LoadedVessels) - { - if(!v || !v.loaded || v == vessel) continue; - - BDModulePilotAI pilot = null; - MissileFire wm = null; - foreach(var p in v.FindPartModulesImplementing()) - { - pilot = p; - break; - } - - if(!pilot) continue; - - foreach(var w in v.FindPartModulesImplementing()) - { - wm = w; - } - - if(!wm || wm.team != weaponManager.team) continue; - friendlies.Add(pilot); - } - - //TEMPORARY - wingmen = new List(); - foreach(var p in friendlies) - { - wingmen.Add(p); - } - } - - void RefreshWingmen() - { - if(wingmen == null) - { - wingmen = new List(); - //focusIndex = 0; - focusIndexes.Clear(); - return; - } - else - { - wingmen.RemoveAll(w => w == null || (w.weaponManager && w.weaponManager.team != weaponManager.team)); - } - - List uniqueIndexes = new List(); - foreach(var focusIndex in focusIndexes) - { - int clampedIndex = Mathf.Clamp(focusIndex, 0, wingmen.Count - 1); - if(!uniqueIndexes.Contains(clampedIndex)) - { - uniqueIndexes.Add(clampedIndex); - } - } - focusIndexes = new List(uniqueIndexes); - - } - - void SaveWingmen(ConfigNode cfg) - { - if(wingmen == null) - { - return; - } - - savedWingmen = string.Empty; - foreach(var pilot in wingmen) - { - savedWingmen += pilot.vessel.id.ToString() + ","; - } - } - - void LoadWingmen() - { - wingmen = new List(); - - if(savedWingmen != string.Empty) - { - string[] wingIDs = savedWingmen.Split(new char[]{ ',' }); - for(int i = 0; i < wingIDs.Length; i++) - { - foreach(Vessel v in BDATargetManager.LoadedVessels) - { - if(!v || !v.loaded) continue; - - if(v.id.ToString() == wingIDs[i]) - { - foreach(var pilot in v.FindPartModulesImplementing()) - { - wingmen.Add(pilot); - break; - } - } - } - } - } - } - - - public bool showGUI = false; - public Rect guiWindowRect; - bool rectInit = false; - float buttonStartY = 30; - float buttonHeight = 24; - float buttonGap = 3; - float margin = 6; - float buttonWidth; - float buttonEndY; - GUIStyle wingmanButtonStyle; - GUIStyle wingmanButtonSelectedStyle; - void OnGUI() - { - if(HighLogic.LoadedSceneIsFlight && vessel && vessel.isActiveVessel && !vessel.packed) - { - if(BDArmorySettings.GAME_UI_ENABLED) - { - if(showGUI) - { - if(!rectInit) - { - guiWindowRect = new Rect(45, 75, 240, 800); - buttonWidth = guiWindowRect.width - (2 * margin); - buttonEndY = buttonStartY; - wingmanButtonStyle = new GUIStyle(HighLogic.Skin.button); - wingmanButtonStyle.alignment = TextAnchor.MiddleLeft; - wingmanButtonStyle.wordWrap = false; - wingmanButtonStyle.fontSize = 11; - wingmanButtonSelectedStyle = new GUIStyle(HighLogic.Skin.box); - wingmanButtonSelectedStyle.alignment = TextAnchor.MiddleLeft; - wingmanButtonSelectedStyle.wordWrap = false; - wingmanButtonSelectedStyle.fontSize = 11; - rectInit = true; - } - guiWindowRect = GUI.Window(1293293, guiWindowRect, WingmenWindow, "WingCommander", HighLogic.Skin.window); - - if(showAGWindow) - { - AGWindow(); - } - } - - //command position diamonds - float diamondSize = 24; - foreach(var comPos in commandedPositions) - { - BDGUIUtils.DrawTextureOnWorldPos(comPos.worldPos, BDArmorySettings.Instance.greenDiamondTexture, new Vector2(diamondSize, diamondSize), 0); - Vector2 labelPos; - if(BDGUIUtils.WorldToGUIPos(comPos.worldPos, out labelPos)) - { - labelPos.x += diamondSize/2; - labelPos.y -= 10; - GUI.Label(new Rect(labelPos.x, labelPos.y, 300, 20), comPos.name); - } - } - - if(drawMouseDiamond) - { - Vector2 mouseDiamondPos = Input.mousePosition; - Rect mouseDiamondRect = new Rect(mouseDiamondPos.x - (diamondSize / 2), Screen.height-mouseDiamondPos.y - (diamondSize / 2), diamondSize, diamondSize); - GUI.DrawTexture(mouseDiamondRect, BDArmorySettings.Instance.greenDiamondTexture, ScaleMode.StretchToFill, true); - } - } - } - } - - delegate void CommandFunction(BDModulePilotAI wingman, int index, object data); - void WingmenWindow(int windowID) - { - float height = buttonStartY; - GUI.DragWindow(new Rect(0, 0, guiWindowRect.width-buttonStartY-margin-margin, buttonStartY)); - - //close buttton - float xSize = buttonStartY - margin - margin; - if(GUI.Button(new Rect(buttonWidth + (2 * buttonGap)-xSize, margin, xSize, xSize), "X", HighLogic.Skin.button)) - { - showGUI = false; - } - - GUI.Box(new Rect(margin-buttonGap, buttonStartY - buttonGap, buttonWidth + (2 * buttonGap), Mathf.Max(wingmen.Count * (buttonHeight + buttonGap), 10)), GUIContent.none, HighLogic.Skin.box); - buttonEndY = buttonStartY; - for(int i = 0; i < wingmen.Count; i++) - { - WingmanButton(i, out buttonEndY); - } - buttonEndY = Mathf.Max(buttonEndY, 15f); - height += buttonEndY; - - //command buttons - float commandButtonLine = 0; - CommandButton(SelectAll, "Select All", ref commandButtonLine, false, false); - //commandButtonLine += 0.25f; - - commandSelf = GUI.Toggle(new Rect(margin, margin + buttonEndY + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth, buttonHeight), commandSelf, "Command Self", HighLogic.Skin.toggle); - commandButtonLine++; - - commandButtonLine += 0.10f; - - CommandButton(CommandFollow, "Follow", ref commandButtonLine, true, false); - CommandButton(CommandFlyTo, "Fly To Pos", ref commandButtonLine, true, waitingForFlytoPos); - CommandButton(CommandAttack, "Attack Pos", ref commandButtonLine, true, waitingForAttackPos); - CommandButton(OpenAGWindow, "Action Group", ref commandButtonLine, false, showAGWindow); - CommandButton(CommandTakeOff, "Take Off", ref commandButtonLine, true, false); - commandButtonLine += 0.5f; - CommandButton(CommandRelease, "Release", ref commandButtonLine, true, false); - - commandButtonLine += 0.5f; - GUI.Label(new Rect(margin, buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth, 20), "Formation Settings:", HighLogic.Skin.label); - commandButtonLine++; - GUI.Label(new Rect(margin, buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth/3, 20), "Spread: "+spread.ToString("0"), HighLogic.Skin.label); - spread = GUI.HorizontalSlider(new Rect(margin + (buttonWidth/3), buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), 2*buttonWidth/3, 20), spread, 20f, 200f, HighLogic.Skin.horizontalSlider, HighLogic.Skin.horizontalSliderThumb); - commandButtonLine++; - GUI.Label(new Rect(margin, buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), buttonWidth/3, 20), "Lag: "+lag.ToString("0"), HighLogic.Skin.label); - lag = GUI.HorizontalSlider(new Rect(margin + (buttonWidth/3), buttonEndY + margin + (commandButtonLine * (buttonHeight + buttonGap)), 2*buttonWidth/3, 20), lag, 0f, 100f, HighLogic.Skin.horizontalSlider, HighLogic.Skin.horizontalSliderThumb); - commandButtonLine++; - - //resize window - height += ((commandButtonLine-1) * (buttonHeight + buttonGap)); - guiWindowRect.height = height; - } - - void WingmanButton(int index, out float buttonEndY) - { - int i = index; - Rect buttonRect = new Rect(margin, buttonStartY + (i * (buttonHeight+buttonGap)), buttonWidth, buttonHeight); - GUIStyle style = (focusIndexes.Contains(i)) ? wingmanButtonSelectedStyle : wingmanButtonStyle; - string label = " "+wingmen[i].vessel.vesselName + " (" + wingmen[i].currentStatus + ")"; - if(GUI.Button(buttonRect, label, style)) - { - if(focusIndexes.Contains(i)) - { - focusIndexes.Remove(i); - } - else - { - focusIndexes.Add(i); - } - } - buttonEndY = buttonStartY + ((i + 1.5f) * buttonHeight); - } - - void CommandButton(CommandFunction func, string buttonLabel, ref float buttonLine, bool sendToWingmen, bool pressed, object data = null) - { - CommandButton(func, buttonLabel, ref buttonLine, buttonEndY, margin, buttonGap, buttonWidth, buttonHeight, sendToWingmen, pressed, data); - } - - void CommandButton(CommandFunction func, string buttonLabel, ref float buttonLine, float startY, float margin, float buttonGap, float buttonWidth, float buttonHeight, bool sendToWingmen, bool pressed, object data) - { - float yPos = startY + margin + ((buttonHeight + buttonGap) * buttonLine); - if(GUI.Button(new Rect(margin, yPos, buttonWidth, buttonHeight), buttonLabel, pressed ? HighLogic.Skin.box : HighLogic.Skin.button)) - { - if(sendToWingmen) - { - if(wingmen.Count > 0) - { - foreach(var index in focusIndexes) - { - func(wingmen[index], index, data); - } - } - - if(commandSelf) - { - foreach(var ai in vessel.FindPartModulesImplementing()) - { - func(ai, -1, data); - } - } - } - else - { - func(null, -1, null); - } - } - - buttonLine++; - } - - void CommandRelease(BDModulePilotAI wingman, int index, object data) - { - wingman.ReleaseCommand(); - } - - void CommandFollow(BDModulePilotAI wingman, int index, object data) - { - wingman.CommandFollow(this, index); - } - - public void CommandAllFollow() - { - RefreshFriendlies(); - int i = 0; - foreach(var wingman in friendlies) - { - wingman.CommandFollow(this, i); - i++; - } - } - - void CommandAG(BDModulePilotAI wingman, int index, object ag) - { - //Debug.Log("object to string: "+ag.ToString()); - KSPActionGroup actionGroup = (KSPActionGroup)ag; - //Debug.Log("ag to string: " + actionGroup.ToString()); - wingman.CommandAG(actionGroup); - } - - void CommandTakeOff(BDModulePilotAI wingman, int index, object data) - { - wingman.ActivatePilot(); - wingman.standbyMode = false; - } - - void OpenAGWindow(BDModulePilotAI wingman, int index, object data) - { - showAGWindow = !showAGWindow; - } - - public bool showAGWindow = false; - float agWindowHeight = 10; - public Rect agWindowRect; - void AGWindow() - { - float width = 100; - float buttonHeight = 20; - float agMargin = 5; - float newHeight = 0; - agWindowRect = new Rect(guiWindowRect.x + guiWindowRect.width, guiWindowRect.y, width, agWindowHeight); - GUI.Box(agWindowRect, string.Empty, HighLogic.Skin.window); - GUI.BeginGroup(agWindowRect); - newHeight += agMargin; - GUIStyle titleStyle = new GUIStyle(HighLogic.Skin.label); - titleStyle.alignment = TextAnchor.MiddleCenter; - GUI.Label(new Rect(agMargin, 5, width - (2*agMargin), 20), "Action Groups", titleStyle); - newHeight += 20; - float startButtonY = newHeight; - float buttonLine = 0; - int i = -1; - foreach(var ag in Enum.GetValues(typeof(KSPActionGroup))) - { - i++; - if(i <= 1) continue; - CommandButton(CommandAG, ag.ToString(), ref buttonLine, startButtonY, agMargin, buttonGap, width-(2*agMargin), buttonHeight, true, false, ag); - newHeight += buttonHeight + buttonGap; - - } - - newHeight += agMargin; - GUI.EndGroup(); - - agWindowHeight = newHeight; - } - - void SelectAll(BDModulePilotAI wingman, int index, object data) - { - for(int i = 0; i < wingmen.Count; i++) - { - if(!focusIndexes.Contains(i)) - { - focusIndexes.Add(i); - } - } - } - - void CommandFlyTo(BDModulePilotAI wingman, int index, object data) - { - StartCoroutine(CommandPosition(wingman, BDModulePilotAI.PilotCommands.FlyTo)); - } - - void CommandAttack(BDModulePilotAI wingman, int index, object data) - { - StartCoroutine(CommandPosition(wingman, BDModulePilotAI.PilotCommands.Attack)); - } - - - bool waitingForFlytoPos = false; - bool waitingForAttackPos = false; - IEnumerator CommandPosition(BDModulePilotAI wingman, BDModulePilotAI.PilotCommands command) - { - if(focusIndexes.Count == 0 && !commandSelf) - { - yield break; - } - - DisplayScreenMessage("Select target coordinates.\nRight-click to cancel."); - - if(command == BDModulePilotAI.PilotCommands.FlyTo) - { - waitingForFlytoPos = true; - } - else if(command == BDModulePilotAI.PilotCommands.Attack) - { - waitingForAttackPos = true; - } - - yield return null; - - bool waitingForPos = true; - drawMouseDiamond = true; - while(waitingForPos) - { - - - if(Input.GetMouseButtonDown(1)) - { - break; - } - if(Input.GetMouseButtonDown(0)) - { - Vector3 mousePos = new Vector3(Input.mousePosition.x/Screen.width, Input.mousePosition.y/Screen.height, 0); - Plane surfPlane = new Plane(vessel.upAxis, vessel.transform.position - (vessel.altitude * vessel.upAxis)); - Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mousePos); - float dist; - if(surfPlane.Raycast(ray, out dist)) - { - Vector3 worldPoint = ray.GetPoint(dist); - Vector3d gps = VectorUtils.WorldPositionToGeoCoords(worldPoint, vessel.mainBody); - - if(command == BDModulePilotAI.PilotCommands.FlyTo) - { - wingman.CommandFlyTo(gps); - } - else if(command == BDModulePilotAI.PilotCommands.Attack) - { - wingman.CommandAttack(gps); - } - - StartCoroutine(CommandPositionGUIRoutine(wingman, new GPSTargetInfo(gps, command.ToString()))); - - } - - break; - } - yield return null; - } - - waitingForAttackPos = false; - waitingForFlytoPos = false; - drawMouseDiamond = false; - ScreenMessages.RemoveMessage(screenMessage); - } - - IEnumerator CommandPositionGUIRoutine(BDModulePilotAI wingman, GPSTargetInfo tInfo) - { - //RemoveCommandPos(tInfo); - commandedPositions.Add(tInfo); - yield return new WaitForSeconds(0.25f); - while(Vector3d.Distance(wingman.commandGPS, tInfo.gpsCoordinates) < 0.01f && (wingman.currentCommand == BDModulePilotAI.PilotCommands.Attack || wingman.currentCommand == BDModulePilotAI.PilotCommands.FlyTo)) - { - yield return null; - } - RemoveCommandPos(tInfo); - } - - - void RemoveCommandPos(GPSTargetInfo tInfo) - { - commandedPositions.RemoveAll(t => t.EqualsTarget(tInfo)); - } - - void DisplayScreenMessage(string message) - { - if(BDArmorySettings.GAME_UI_ENABLED && vessel == FlightGlobals.ActiveVessel) - { - ScreenMessages.RemoveMessage(screenMessage); - screenMessage.message = message; - ScreenMessages.PostScreenMessage(screenMessage); - } - } - } -} - diff --git a/BahaTurret/ObjectPool.cs b/BahaTurret/ObjectPool.cs deleted file mode 100644 index 5c4a74f8c..000000000 --- a/BahaTurret/ObjectPool.cs +++ /dev/null @@ -1,100 +0,0 @@ -using UnityEngine; -using System.Collections; -using System.Collections.Generic; - -namespace BahaTurret -{ - public class ObjectPool : MonoBehaviour - { - public GameObject poolObject; - public int size; - public bool canGrow; - - List pool; - - public string poolObjectName; - - - void Awake() - { - pool = new List(); - } - - void Start() - { - for(int i = 0; i < size; i++) - { - GameObject obj = (GameObject)Instantiate(poolObject); - obj.transform.SetParent(transform); - obj.SetActive(false); - pool.Add(obj); - } - } - - public GameObject GetPooledObject(int index) - { - return pool[index]; - } - - - public GameObject GetPooledObject() - { - for(int i = 0; i < pool.Count; i++) - { - if(!pool[i].activeInHierarchy) - { - //pool[i].SetActive(true); - return pool[i]; - } - } - - if(canGrow) - { - if(!poolObject) - { - Debug.LogWarning("Tried to instantiate a pool object but prefab is missing! ("+poolObjectName+")"); - } - GameObject obj = (GameObject)Instantiate(poolObject); - obj.transform.SetParent(transform); - obj.SetActive(false); - //obj.SetActive(true); - pool.Add(obj); - size++; - return obj; - } - - return null; - } - - public void DisableAfterDelay(GameObject obj, float t) - { - StartCoroutine(DisableObject(obj, t)); - } - - IEnumerator DisableObject(GameObject obj, float t) - { - yield return new WaitForSeconds(t); - if(obj) - { - obj.SetActive(false); - obj.transform.parent = transform; - } - } - - public static ObjectPool CreateObjectPool(GameObject obj, int size, bool canGrow, bool destroyOnLoad) - { - GameObject poolObject = new GameObject(obj.name+"Pool"); - ObjectPool op = poolObject.AddComponent(); - op.poolObject = obj; - op.size = size; - op.canGrow = canGrow; - op.poolObjectName = obj.name; - if(!destroyOnLoad) - { - GameObject.DontDestroyOnLoad(poolObject); - } - - return op; - } - } -} diff --git a/BahaTurret/ParticleTurbulence.cs b/BahaTurret/ParticleTurbulence.cs deleted file mode 100644 index 640448a58..000000000 --- a/BahaTurret/ParticleTurbulence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - [KSPAddon(KSPAddon.Startup.Flight, false)] - public class ParticleTurbulence : MonoBehaviour - { - public static Vector3 flareTurbulence = Vector3.zero; - float flareTurbulenceX = 0; - float flareTurbulenceY = 0; - float flareTurbulenceZ = 0; - float flareTurbDelta = 0.2f; - float flareTurbTimer = 0; - - public static Vector3 Turbulence - { - get - { - float x = VectorUtils.FullRangePerlinNoise(Time.time*0.5F, 0); - float y = VectorUtils.FullRangePerlinNoise(Time.time*1.1f, 35); - float z = VectorUtils.FullRangePerlinNoise(Time.time*0.75f, 70); - return new Vector3(x,y,z) * 5; - } - } - - - - void FixedUpdate() - { - - //if(BDArmorySettings.numberOfParticleEmitters > 0) - //{ - if(Time.time-flareTurbTimer > flareTurbDelta) - { - flareTurbTimer = Time.time; - - if(flareTurbulenceX >= 1) flareTurbulenceX = Mathf.Clamp(1 - UnityEngine.Random.Range(0f,2f), 0, 1); - else if(flareTurbulenceX <= -1) flareTurbulenceX = Mathf.Clamp (-1 + UnityEngine.Random.Range(0f,2f), -1, 1); - else flareTurbulenceX += Mathf.Clamp (UnityEngine.Random.Range(-1f,1f), -1, 1); - - if(flareTurbulenceY >= 1) flareTurbulenceY = Mathf.Clamp(1 - UnityEngine.Random.Range(0f,2f), 0, 1); - else if(flareTurbulenceY <= -1) flareTurbulenceY = Mathf.Clamp (-1 + UnityEngine.Random.Range(0f,2f), -1, 1); - else flareTurbulenceY += Mathf.Clamp (UnityEngine.Random.Range(-1f,1f), -1, 1); - - if(flareTurbulenceZ >= 1) flareTurbulenceZ = Mathf.Clamp(1 - UnityEngine.Random.Range(0f,2f), 0, 1); - else if(flareTurbulenceZ <= -1) flareTurbulenceZ = Mathf.Clamp (-1 + UnityEngine.Random.Range(0f,2f), -1, 1); - else flareTurbulenceZ += Mathf.Clamp (UnityEngine.Random.Range(-1f,1f), -1, 1); - } - - flareTurbulence = Vector3.Lerp(flareTurbulence, new Vector3(flareTurbulenceX, flareTurbulenceY, flareTurbulenceZ), UnityEngine.Random.Range(2.5f,7.5f) * TimeWarp.fixedDeltaTime); - - //wind - - - //} - } - } -} - diff --git a/BahaTurret/PooledBullet.cs b/BahaTurret/PooledBullet.cs deleted file mode 100644 index c309f22db..000000000 --- a/BahaTurret/PooledBullet.cs +++ /dev/null @@ -1,515 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; - -namespace BahaTurret -{ - public class PooledBullet : MonoBehaviour - { - public enum PooledBulletTypes{Standard, Explosive} - public enum BulletDragTypes { None, AnalyticEstimate, NumericalIntegration } - - public PooledBulletTypes bulletType; - public BulletDragTypes dragType; - - public Vessel sourceVessel; - public Color lightColor = Misc.ParseColor255("255, 235, 145, 255"); - public Color projectileColor; - - public string bulletTexturePath; - - public bool fadeColor; - public Color startColor; - Color currentColor; - - public bool bulletDrop = true; - - public float tracerStartWidth = 1; - public float tracerEndWidth = 1; - public float tracerLength = 0; - public float tracerDeltaFactor = 1.35f; - public float tracerLuminance = 1; - - public float initialSpeed; - - - public Vector3 prevPosition; - public Vector3 currPosition; - - //explosive parameters - public float radius = 30; - public float blastPower = 8; - public float blastHeat = -1; - - public string explModelPath; - public string explSoundPath; - // - - Vector3 startPosition; - public bool airDetonation = false; - public float detonationRange = 3500; - - float randomWidthScale = 1; - - LineRenderer bulletTrail; - // VectorLine bulletVectorLine; - //Material lineMat; - - - Vector3 sourceOriginalV; - bool hasBounced = false; - - float maxDistance; - - //bool isUnderwater = false; - - Light lightFlash; - bool wasInitiated = false; - - //physical properties - public Vector3 currentVelocity; - public float mass; - public float ballisticCoefficient; - - public float flightTimeElapsed = 0; - - bool collisionEnabled = false; - - public static Shader bulletShader; - public static bool shaderInitialized = false; - - void OnEnable() - { - startPosition = transform.position; - collisionEnabled = false; - - maxDistance = Mathf.Clamp(BDArmorySettings.PHYSICS_RANGE, 2500, BDArmorySettings.MAX_BULLET_RANGE); - if(!wasInitiated) - { - //projectileColor.a = projectileColor.a/2; - //startColor.a = startColor.a/2; - } - - projectileColor.a = Mathf.Clamp(projectileColor.a, 0.25f, 1f); - startColor.a = Mathf.Clamp(startColor.a, 0.25f, 1f); - currentColor = projectileColor; - if(fadeColor) - { - currentColor = startColor; - } - - prevPosition = gameObject.transform.position; - - sourceOriginalV = sourceVessel.rb_velocity; - - if(!lightFlash) - { - lightFlash = gameObject.AddComponent(); - lightFlash.type = LightType.Point; - lightFlash.range = 8; - lightFlash.intensity = 1; - } - lightFlash.color = lightColor; - lightFlash.enabled = true; - - - //tracer setup - if(!bulletTrail) - { - bulletTrail = gameObject.AddComponent(); - } - if(!wasInitiated) - { - bulletTrail.SetVertexCount(2); - } - bulletTrail.SetPosition(0, transform.position); - bulletTrail.SetPosition(1, transform.position); - - //float width = tracerStartWidth * Vector3.Distance(transform.position, FlightCamera.fetch.mainCamera.transform.position)/50; - //bulletTrail.SetWidth(width, width); - - if(!shaderInitialized) - { - shaderInitialized = true; - bulletShader = BDAShaderLoader.BulletShader;//.LoadManifestShader("BahaTurret.BulletShader.shader"); - } - - if(!wasInitiated) - { - //bulletTrail.material = new Material(Shader.Find("KSP/Particles/Alpha Blended")); - bulletTrail.material = new Material(bulletShader); - - randomWidthScale = UnityEngine.Random.Range(0.5f, 1f); - gameObject.layer = 15; - } - - bulletTrail.material.mainTexture = GameDatabase.Instance.GetTexture(bulletTexturePath, false); - bulletTrail.material.SetColor("_TintColor", currentColor); - bulletTrail.material.SetFloat("_Lum", tracerLuminance); - - tracerStartWidth *= 2f; - tracerEndWidth *= 2f; - - hasBounced = false; - - - - wasInitiated = true; - - StartCoroutine(FrameDelayedRoutine()); - } - - IEnumerator FrameDelayedRoutine() - { - yield return new WaitForFixedUpdate(); - lightFlash.enabled = false; - collisionEnabled = true; - } - - void OnWillRenderObject() - { - if(!gameObject.activeInHierarchy) - { - return; - } - Camera currentCam = Camera.current; - if(TargetingCamera.IsTGPCamera(currentCam)) - { - UpdateWidth(currentCam, 4); - } - else - { - UpdateWidth(currentCam, 1); - } - } - - - void FixedUpdate() - { - float distanceFromStart = Vector3.Distance(transform.position, startPosition); - if(!gameObject.activeInHierarchy) - { - return; - } - flightTimeElapsed += TimeWarp.fixedDeltaTime; //calculate flight time for drag purposes - - if(bulletDrop && FlightGlobals.RefFrameIsRotating) - { - currentVelocity += FlightGlobals.getGeeForceAtPosition(transform.position) * TimeWarp.fixedDeltaTime; - } - if(dragType == BulletDragTypes.NumericalIntegration) - { - Vector3 dragAcc = currentVelocity * currentVelocity.magnitude * (float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), FlightGlobals.getExternalTemperature(transform.position)); - dragAcc *= 0.5f; - dragAcc /= ballisticCoefficient; - - currentVelocity -= dragAcc * TimeWarp.fixedDeltaTime; //numerical integration; using Euler is silly, but let's go with it anyway - } - - - if(tracerLength == 0) - { - bulletTrail.SetPosition(0, transform.position+(currentVelocity * tracerDeltaFactor * TimeWarp.fixedDeltaTime/TimeWarp.CurrentRate)-(FlightGlobals.ActiveVessel.rb_velocity*TimeWarp.fixedDeltaTime)); - } - else - { - bulletTrail.SetPosition(0, transform.position + ((currentVelocity-sourceOriginalV).normalized * tracerLength)); - } - if(fadeColor) - { - FadeColor(); - bulletTrail.material.SetColor("_TintColor", currentColor * tracerLuminance); - } - - - - bulletTrail.SetPosition(1, transform.position); - - - - currPosition = gameObject.transform.position; - - if(distanceFromStart > maxDistance) - { - //GameObject.Destroy(gameObject); - KillBullet(); - return; - } - - if(collisionEnabled) - { - float dist = initialSpeed*TimeWarp.fixedDeltaTime; - - Ray ray = new Ray(prevPosition, currPosition-prevPosition); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, dist, 557057)) - { - bool penetrated = true; - Part hitPart = null; //determine when bullet collides with a target - float hitAngle = Vector3.Angle(currentVelocity, -hit.normal); - - if(bulletType != PooledBulletTypes.Explosive) //dont do bullet damage if it is explosive - { - float impactVelocity = currentVelocity.magnitude; - if(dragType == BulletDragTypes.AnalyticEstimate) - { - float analyticDragVelAdjustment = (float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(currPosition), FlightGlobals.getExternalTemperature(currPosition)); - analyticDragVelAdjustment *= flightTimeElapsed * initialSpeed; - analyticDragVelAdjustment += 2 * ballisticCoefficient; - - analyticDragVelAdjustment = 2 * ballisticCoefficient * initialSpeed / analyticDragVelAdjustment; //velocity as a function of time under the assumption of a projectile only acted upon by drag with a constant drag area - - analyticDragVelAdjustment = analyticDragVelAdjustment - initialSpeed; //since the above was velocity as a function of time, but we need a difference in drag, subtract the initial velocity - //the above number should be negative... - impactVelocity += analyticDragVelAdjustment; //so add it to the impact velocity - - if(impactVelocity < 0) - { - impactVelocity = 0; //clamp the velocity to > 0, since it could drop below 0 if the bullet is fired upwards - } - //Debug.Log("flight time: " + flightTimeElapsed + " BC: " + ballisticCoefficient + "\ninit speed: " + initialSpeed + " vel diff: " + analyticDragVelAdjustment); - } - - //hitting a vessel Part - - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////[panzer1b] HEAT BASED DAMAGE CODE START////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - try - { - hitPart = Part.FromGO(hit.rigidbody.gameObject); - } - catch(NullReferenceException) - { - } - - - if(hitPart != null) //see if it will ricochet of the part - { - penetrated = !RicochetOnPart(hitPart, hitAngle, impactVelocity); - } - else //see if it will ricochet off scenery - { - float reflectRandom = UnityEngine.Random.Range(-150f, 90f); - if(reflectRandom > 90 - hitAngle) - { - penetrated = false; - } - } - - - if(hitPart != null && !hitPart.partInfo.name.Contains("Strut")) //when a part is hit, execute damage code (ignores struts to keep those from being abused as armor)(no, because they caused weird bugs :) -BahamutoD) - { - float heatDamage = (mass / (hitPart.crashTolerance * hitPart.mass)) * impactVelocity * impactVelocity * BDArmorySettings.DMG_MULTIPLIER; //how much heat damage will be applied based on bullet mass, velocity, and part's impact tolerance and mass - if(!penetrated) - { - heatDamage = heatDamage / 8; - } - if(BDArmorySettings.INSTAKILL) //instakill support, will be removed once mod becomes officially MP - { - heatDamage = (float)hitPart.maxTemp + 100; //make heat damage equal to the part's max temperture, effectively instakilling any part it hits - } - if(BDArmorySettings.DRAW_DEBUG_LABELS) Debug.Log("Hit! damage applied: " + heatDamage); //debugging stuff - - if(hitPart.vessel != sourceVessel) hitPart.temperature += heatDamage; //apply heat damage to the hit part. - - float overKillHeatDamage = (float)(hitPart.temperature - hitPart.maxTemp); - - if(overKillHeatDamage > 0) //if the part is destroyed by overheating, we want to add the remaining heat to attached parts. This prevents using tiny parts as armor - { - overKillHeatDamage *= hitPart.crashTolerance; //reset to raw damage - float numConnectedParts = hitPart.children.Count; - if(hitPart.parent != null) - { - numConnectedParts++; - overKillHeatDamage /= numConnectedParts; - hitPart.parent.temperature += overKillHeatDamage / (hitPart.parent.crashTolerance * hitPart.parent.mass); - - for(int i = 0; i < hitPart.children.Count; i++) - { - hitPart.children[i].temperature += overKillHeatDamage / hitPart.children[i].crashTolerance; - } - } - else - { - overKillHeatDamage /= numConnectedParts; - for(int i = 0; i < hitPart.children.Count; i++) - { - hitPart.children[i].temperature += overKillHeatDamage / hitPart.children[i].crashTolerance; - } - } - } - - } - - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////[panzer1b] HEAT BASED DAMAGE CODE END//////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - //hitting a Building - DestructibleBuilding hitBuilding = null; - try - { - hitBuilding = hit.collider.gameObject.GetComponentUpwards(); - } - catch(NullReferenceException) - { - } - if(hitBuilding != null && hitBuilding.IsIntact) - { - float damageToBuilding = mass * initialSpeed * initialSpeed * BDArmorySettings.DMG_MULTIPLIER / 12000; - if(!penetrated) - { - damageToBuilding = damageToBuilding / 8; - } - hitBuilding.AddDamage(damageToBuilding); - if(hitBuilding.Damage > hitBuilding.impactMomentumThreshold) - { - hitBuilding.Demolish(); - } - if(BDArmorySettings.DRAW_DEBUG_LINES) Debug.Log("bullet hit destructible building! Damage: " + (damageToBuilding).ToString("0.00") + ", total Damage: " + hitBuilding.Damage); - } - - } - - if(hitPart == null || (hitPart!=null && hitPart.vessel!=sourceVessel)) - { - if(!penetrated && !hasBounced) - { - //ricochet - hasBounced = true; - if(BDArmorySettings.BULLET_HITS) - { - BulletHitFX.CreateBulletHit(hit.point, hit.normal, true); - } - - tracerStartWidth /= 2; - tracerEndWidth /= 2; - - transform.position = hit.point; - currentVelocity = Vector3.Reflect(currentVelocity, hit.normal); - currentVelocity = (hitAngle/150) * currentVelocity * 0.65f; - - Vector3 randomDirection = UnityEngine.Random.rotation * Vector3.one; - - currentVelocity = Vector3.RotateTowards(currentVelocity, randomDirection, UnityEngine.Random.Range(0f,5f)*Mathf.Deg2Rad, 0); - } - else - { - if(bulletType == PooledBulletTypes.Explosive) - { - ExplosionFX.CreateExplosion(hit.point - (ray.direction*0.1f), radius, blastPower, blastHeat, sourceVessel, currentVelocity.normalized, explModelPath, explSoundPath); - } - else if(BDArmorySettings.BULLET_HITS) - { - BulletHitFX.CreateBulletHit(hit.point, hit.normal, false); - } - - - - //GameObject.Destroy(gameObject); //destroy bullet on collision - KillBullet(); - return; - } - } - } - - /* - if(isUnderwater) - { - if(FlightGlobals.getAltitudeAtPos(transform.position) > 0) - { - isUnderwater = false; - } - else - { - rigidbody.AddForce(-rigidbody.velocity * 0.15f); - } - } - else - { - if(FlightGlobals.getAltitudeAtPos(transform.position) < 0) - { - isUnderwater = true; - //FXMonger.Splash(transform.position, 1); - //make a custom splash here - } - } - */ - } - - if(bulletType == PooledBulletTypes.Explosive && airDetonation && distanceFromStart > detonationRange) - { - //detonate - ExplosionFX.CreateExplosion(transform.position, radius, blastPower, blastHeat, sourceVessel, currentVelocity.normalized, explModelPath, explSoundPath); - //GameObject.Destroy(gameObject); //destroy bullet on collision - KillBullet(); - return; - } - - - prevPosition = currPosition; - - //move bullet - transform.position += currentVelocity*Time.fixedDeltaTime; - } - - - public void UpdateWidth(Camera c, float resizeFactor) - { - if(!gameObject.activeInHierarchy) - { - return; - } - - float fov = c.fieldOfView; - float factor = (fov/60) * resizeFactor * Mathf.Clamp(Vector3.Distance(transform.position, c.transform.position),0,3000)/50; - float width1 = tracerStartWidth * factor * randomWidthScale; - float width2 = tracerEndWidth * factor * randomWidthScale; - - bulletTrail.SetWidth(width1, width2); - } - - - void KillBullet() - { - gameObject.SetActive(false); - } - - - - - - - void FadeColor() - { - Vector4 currentColorV = new Vector4(currentColor.r, currentColor.g, currentColor.b, currentColor.a); - Vector4 endColorV = new Vector4(projectileColor.r, projectileColor.g, projectileColor.b, projectileColor.a); - //float delta = (Vector4.Distance(currentColorV, endColorV)/0.15f) * TimeWarp.fixedDeltaTime; - float delta = TimeWarp.fixedDeltaTime; - Vector4 finalColorV = Vector4.MoveTowards(currentColor, endColorV, delta); - currentColor = new Color(finalColorV.x, finalColorV.y, finalColorV.z, Mathf.Clamp(finalColorV.w, 0.25f, 1f)); - } - - bool RicochetOnPart(Part p, float angleFromNormal, float impactVel) - { - float hitTolerance = p.crashTolerance; - //15 degrees should virtually guarantee a ricochet, but 75 degrees should nearly always be fine - float chance = (((angleFromNormal - 5) / 75) * (hitTolerance / 150)) * 100 / Mathf.Clamp01(impactVel / 600); - float random = UnityEngine.Random.Range(0f,100f); - //Debug.Log ("Ricochet chance: "+chance); - if(random < chance) - { - return true; - } - else - { - return false; - } - } - } -} - diff --git a/BahaTurret/RadarDisplayData.cs b/BahaTurret/RadarDisplayData.cs deleted file mode 100644 index 6e5a94058..000000000 --- a/BahaTurret/RadarDisplayData.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public struct RadarDisplayData - { - public Vessel vessel; - public Vector2 pingPosition; - public bool locked; - public ModuleRadar detectedByRadar; - public TargetSignatureData targetData; - public float signalPersistTime; - } -} - diff --git a/BahaTurret/RadarUtils.cs b/BahaTurret/RadarUtils.cs deleted file mode 100644 index 5d5b1402e..000000000 --- a/BahaTurret/RadarUtils.cs +++ /dev/null @@ -1,554 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections.Generic; -using UnityEngine; -namespace BahaTurret -{ - public static class RadarUtils - { - - public static RenderTexture radarRT; - public static Texture2D radarTex2D; - public static Camera radarCam; - public static Shader radarShader; - public static int radarResolution = 32; - - - - public static void SetupRadarCamera() - { - if(radarRT && radarTex2D && radarCam && radarShader) - { - return; - } - - //setup shader first - if(!radarShader) - { - radarShader = BDAShaderLoader.UnlitBlackShader;//.LoadManifestShader("BahaTurret.UnlitBlack.shader"); - } - - //then setup textures - radarRT = new RenderTexture(radarResolution,radarResolution,16); - radarTex2D = new Texture2D(radarResolution,radarResolution, TextureFormat.ARGB32, false); - - //set up camera - radarCam = (new GameObject("RadarCamera")).AddComponent(); - radarCam.enabled = false; - radarCam.clearFlags = CameraClearFlags.SolidColor; - radarCam.backgroundColor = Color.white; - radarCam.SetReplacementShader(radarShader, string.Empty); - radarCam.cullingMask = 1<<0; - radarCam.targetTexture = radarRT; - //radarCam.nearClipPlane = 75; - //radarCam.farClipPlane = 40000; - } - - public static float GetRadarSnapshot(Vessel v, Vector3 origin, float camFoV) - { - - TargetInfo ti = v.GetComponent(); - if(ti && ti.isMissile) - { - return 600; - } - - float distance = (v.transform.position - origin).magnitude; - - radarCam.nearClipPlane = Mathf.Clamp(distance - 200, 20, 40000); - radarCam.farClipPlane = Mathf.Clamp(distance + 200, 20, 40000); - - radarCam.fieldOfView = camFoV; - - radarCam.transform.position = origin; - radarCam.transform.LookAt(v.CoM+(v.rb_velocity*Time.fixedDeltaTime)); - - float pixels = 0; - RenderTexture.active = radarRT; - - radarCam.Render(); - - radarTex2D.ReadPixels(new Rect(0,0,radarResolution,radarResolution), 0,0); - - for(int x = 0; x < radarResolution; x++) - { - for(int y = 0; y < radarResolution; y++) - { - if(radarTex2D.GetPixel(x,y).r<1) - { - pixels++; - } - } - } - - - return pixels*4; - } - - - public static void UpdateRadarLock(MissileFire myWpnManager, float directionAngle, Transform referenceTransform, float fov, Vector3 position, float minSignature, ref TargetSignatureData[] dataArray, float dataPersistTime, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType, bool radarSnapshot) - { - Vector3d geoPos = VectorUtils.WorldPositionToGeoCoords(position, FlightGlobals.currentMainBody); - Vector3 forwardVector = referenceTransform.forward; - Vector3 upVector = referenceTransform.up;//VectorUtils.GetUpDirection(position); - Vector3 lookDirection = Quaternion.AngleAxis(directionAngle, upVector) * forwardVector; - - int dataIndex = 0; - foreach(var vessel in BDATargetManager.LoadedVessels) - { - if(vessel == null) continue; - if(!vessel.loaded) continue; - - if(myWpnManager) - { - if(vessel == myWpnManager.vessel) continue; //ignore self - } - else if((vessel.transform.position - position).sqrMagnitude < 3600) continue; - - Vector3 vesselDirection = Vector3.ProjectOnPlane(vessel.CoM - position, upVector); - - if(Vector3.Angle(vesselDirection, lookDirection) < fov / 2) - { - if(TerrainCheck(referenceTransform.position, vessel.transform.position)) continue; //blocked by terrain - - float sig = float.MaxValue; - if(radarSnapshot && minSignature > 0) sig = GetModifiedSignature(vessel, position); - - RadarWarningReceiver.PingRWR(vessel, position, rwrType, dataPersistTime); - - float detectSig = sig; - - VesselECMJInfo vesselJammer = vessel.GetComponent(); - if(vesselJammer) - { - sig *= vesselJammer.rcsReductionFactor; - detectSig += vesselJammer.jammerStrength; - } - - if(detectSig > minSignature) - { - if(vessel.vesselType == VesselType.Debris) - { - vessel.gameObject.AddComponent(); - } - else if(myWpnManager != null) - { - BDATargetManager.ReportVessel(vessel, myWpnManager); - } - - while(dataIndex < dataArray.Length - 1) - { - if((dataArray[dataIndex].exists && Time.time - dataArray[dataIndex].timeAcquired > dataPersistTime) || !dataArray[dataIndex].exists) - { - break; - } - dataIndex++; - } - if(dataIndex >= dataArray.Length) break; - dataArray[dataIndex] = new TargetSignatureData(vessel, sig); - dataIndex++; - if(dataIndex >= dataArray.Length) break; - } - } - } - - } - - public static void UpdateRadarLock(MissileFire myWpnManager, float directionAngle, Transform referenceTransform, float fov, Vector3 position, float minSignature, ModuleRadar radar, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType, bool radarSnapshot) - { - Vector3d geoPos = VectorUtils.WorldPositionToGeoCoords(position, FlightGlobals.currentMainBody); - Vector3 forwardVector = referenceTransform.forward; - Vector3 upVector = referenceTransform.up;//VectorUtils.GetUpDirection(position); - Vector3 lookDirection = Quaternion.AngleAxis(directionAngle, upVector) * forwardVector; - - foreach(var vessel in BDATargetManager.LoadedVessels) - { - if(vessel == null) continue; - if(!vessel.loaded) continue; - - if(myWpnManager) - { - if(vessel == myWpnManager.vessel) continue; //ignore self - } - else if((vessel.transform.position - position).sqrMagnitude < 3600) continue; - - Vector3 vesselDirection = Vector3.ProjectOnPlane(vessel.CoM - position, upVector); - - if(Vector3.Angle(vesselDirection, lookDirection) < fov / 2) - { - if(TerrainCheck(referenceTransform.position, vessel.transform.position)) continue; //blocked by terrain - - float sig = float.MaxValue; - if(radarSnapshot && minSignature > 0) sig = GetModifiedSignature(vessel, position); - - RadarWarningReceiver.PingRWR(vessel, position, rwrType, radar.signalPersistTime); - - float detectSig = sig; - - VesselECMJInfo vesselJammer = vessel.GetComponent(); - if(vesselJammer) - { - sig *= vesselJammer.rcsReductionFactor; - detectSig += vesselJammer.jammerStrength; - } - - if(detectSig > minSignature) - { - if(vessel.vesselType == VesselType.Debris) - { - vessel.gameObject.AddComponent(); - } - else if(myWpnManager != null) - { - BDATargetManager.ReportVessel(vessel, myWpnManager); - } - - //radar.vesselRadarData.AddRadarContact(radar, new TargetSignatureData(vessel, detectSig), false); - radar.ReceiveContactData(new TargetSignatureData(vessel, detectSig), false); - } - } - } - - } - - public static void UpdateRadarLock(Ray ray, float fov, float minSignature, ref TargetSignatureData[] dataArray, float dataPersistTime, bool pingRWR, RadarWarningReceiver.RWRThreatTypes rwrType, bool radarSnapshot) - { - int dataIndex = 0; - foreach(var vessel in BDATargetManager.LoadedVessels) - { - if(vessel == null) continue; - if(!vessel.loaded) continue; - //if(vessel.Landed) continue; - - Vector3 vectorToTarget = vessel.transform.position - ray.origin; - if((vectorToTarget).sqrMagnitude < 10) continue; //ignore self - - if(Vector3.Dot(vectorToTarget, ray.direction) < 0) continue; //ignore behind ray - - if(Vector3.Angle(vessel.CoM - ray.origin, ray.direction) < fov / 2) - { - if(TerrainCheck(ray.origin, vessel.transform.position)) continue; //blocked by terrain - float sig = float.MaxValue; - if(radarSnapshot) sig = GetModifiedSignature(vessel, ray.origin); - - if(pingRWR && sig > minSignature * 0.66f) - { - RadarWarningReceiver.PingRWR(vessel, ray.origin, rwrType, dataPersistTime); - } - - if(sig > minSignature) - { - while(dataIndex < dataArray.Length - 1) - { - if((dataArray[dataIndex].exists && Time.time - dataArray[dataIndex].timeAcquired > dataPersistTime) || !dataArray[dataIndex].exists) - { - break; - } - dataIndex++; - } - if(dataIndex >= dataArray.Length) break; - dataArray[dataIndex] = new TargetSignatureData(vessel, sig); - dataIndex++; - if(dataIndex >= dataArray.Length) break; - } - } - - } - } - - public static void UpdateRadarLock(Ray ray, Vector3 predictedPos, float fov, float minSignature, ModuleRadar radar, bool pingRWR, bool radarSnapshot, float dataPersistTime, bool locked, int lockIndex, Vessel lockedVessel) - { - RadarWarningReceiver.RWRThreatTypes rwrType = radar.rwrType; - //Vessel lockedVessel = null; - float closestSqrDist = 100; - - if(lockedVessel == null) - { - foreach(var vessel in BDATargetManager.LoadedVessels) - { - if(vessel == null) continue; - if(!vessel.loaded) continue; - //if(vessel.Landed) continue; - - Vector3 vectorToTarget = vessel.transform.position - ray.origin; - if((vectorToTarget).sqrMagnitude < 10) continue; //ignore self - - if(Vector3.Dot(vectorToTarget, ray.direction) < 0) continue; //ignore behind ray - - if(Vector3.Angle(vessel.CoM - ray.origin, ray.direction) < fov / 2) - { - float sqrDist = Vector3.SqrMagnitude(vessel.CoM - predictedPos); - if(sqrDist < closestSqrDist) - { - closestSqrDist = sqrDist; - lockedVessel = vessel; - } - } - } - } - - if(lockedVessel != null) - { - if(TerrainCheck(ray.origin, lockedVessel.transform.position)) - { - radar.UnlockTargetAt(lockIndex, true); //blocked by terrain - return; - } - - float sig = float.MaxValue; - if(radarSnapshot) sig = GetModifiedSignature(lockedVessel, ray.origin); - - if(pingRWR && sig > minSignature * 0.66f) - { - RadarWarningReceiver.PingRWR(lockedVessel, ray.origin, rwrType, dataPersistTime); - } - - if(sig > minSignature) - { - //radar.vesselRadarData.AddRadarContact(radar, new TargetSignatureData(lockedVessel, sig), locked); - radar.ReceiveContactData(new TargetSignatureData(lockedVessel, sig), locked); - } - else - { - radar.UnlockTargetAt(lockIndex, true); - return; - } - } - else - { - radar.UnlockTargetAt(lockIndex, true); - } - } - - /// - /// Scans for targets in direction with field of view. - /// Returns the direction scanned for debug - /// - /// The scan direction. - /// My wpn manager. - /// Direction angle. - /// Reference transform. - /// Fov. - /// Results. - /// Max distance. - public static Vector3 GuardScanInDirection(MissileFire myWpnManager, float directionAngle, Transform referenceTransform, float fov, out ViewScanResults results, float maxDistance) - { - fov *= 1.1f; - results = new ViewScanResults(); - results.foundMissile = false; - results.foundHeatMissile = false; - results.foundRadarMissile = false; - results.foundAGM = false; - results.firingAtMe = false; - results.missileThreatDistance = float.MaxValue; - results.threatVessel = null; - results.threatWeaponManager = null; - - if(!myWpnManager || !referenceTransform) - { - return Vector3.zero; - } - - Vector3 position = referenceTransform.position; - Vector3d geoPos = VectorUtils.WorldPositionToGeoCoords(position, FlightGlobals.currentMainBody); - Vector3 forwardVector = referenceTransform.forward; - Vector3 upVector = referenceTransform.up; - Vector3 lookDirection = Quaternion.AngleAxis(directionAngle, upVector) * forwardVector; - - - - foreach(var vessel in BDATargetManager.LoadedVessels) - { - if(vessel == null) continue; - - if(vessel.loaded) - { - if(vessel == myWpnManager.vessel) continue; //ignore self - - Vector3 vesselProjectedDirection = Vector3.ProjectOnPlane(vessel.transform.position-position, upVector); - Vector3 vesselDirection = vessel.transform.position - position; - - - if(Vector3.Dot(vesselDirection, lookDirection) < 0) continue; - - float vesselDistance = (vessel.transform.position - position).magnitude; - - if(vesselDistance < maxDistance && Vector3.Angle(vesselProjectedDirection, lookDirection) < fov / 2 && Vector3.Angle(vessel.transform.position-position, -myWpnManager.transform.forward) < myWpnManager.guardAngle/2) - { - //Debug.Log("Found vessel: " + vessel.vesselName); - if(TerrainCheck(referenceTransform.position, vessel.transform.position)) continue; //blocked by terrain - - BDATargetManager.ReportVessel(vessel, myWpnManager); - - TargetInfo tInfo; - if((tInfo = vessel.GetComponent())) - { - if(tInfo.isMissile) - { - MissileLauncher missile; - if(missile = tInfo.missileModule) - { - results.foundMissile = true; - results.threatVessel = missile.vessel; - Vector3 vectorFromMissile = myWpnManager.vessel.CoM - missile.part.transform.position; - Vector3 relV = missile.vessel.srf_velocity - myWpnManager.vessel.srf_velocity; - bool approaching = Vector3.Dot(relV, vectorFromMissile) > 0; - if(missile.hasFired && missile.timeIndex > 1 && approaching && (missile.targetPosition - (myWpnManager.vessel.CoM + (myWpnManager.vessel.rb_velocity * Time.fixedDeltaTime))).sqrMagnitude < 3600) - { - if(missile.targetingMode == MissileLauncher.TargetingModes.Heat) - { - results.foundHeatMissile = true; - results.missileThreatDistance = Mathf.Min(results.missileThreatDistance, Vector3.Distance(missile.part.transform.position, myWpnManager.part.transform.position)); - results.threatPosition = missile.transform.position; - break; - } - else if(missile.targetingMode == MissileLauncher.TargetingModes.Radar) - { - results.foundRadarMissile = true; - results.missileThreatDistance = Mathf.Min(results.missileThreatDistance, Vector3.Distance(missile.part.transform.position, myWpnManager.part.transform.position)); - results.threatPosition = missile.transform.position; - } - else if(missile.targetingMode == MissileLauncher.TargetingModes.Laser) - { - results.foundAGM = true; - results.missileThreatDistance = Mathf.Min(results.missileThreatDistance, Vector3.Distance(missile.part.transform.position, myWpnManager.part.transform.position)); - break; - } - } - else - { - break; - } - } - } - else - { - //check if its shooting guns at me - //if(!results.firingAtMe) //more work, but we can't afford to be incorrect picking the closest threat - //{ - foreach(var weapon in vessel.FindPartModulesImplementing()) - { - if(!weapon.recentlyFiring) continue; - if(Vector3.Dot(weapon.fireTransforms[0].forward, vesselDirection) > 0) continue; - - if(Vector3.Angle(weapon.fireTransforms[0].forward, -vesselDirection) < 6500 / vesselDistance && (!results.firingAtMe || (weapon.vessel.ReferenceTransform.position - position).magnitude < (results.threatPosition - position).magnitude)) - { - results.firingAtMe = true; - results.threatPosition = weapon.vessel.transform.position; - results.threatVessel = weapon.vessel; - results.threatWeaponManager = weapon.weaponManager; - break; - } - } - //} - } - } - } - } - } - - return lookDirection; - } - - public static float GetModifiedSignature(Vessel vessel, Vector3 origin) - { - //float sig = GetBaseRadarSignature(vessel); - float sig = GetRadarSnapshot(vessel, origin, 0.1f); - - Vector3 upVector = VectorUtils.GetUpDirection(origin); - - //sig *= Mathf.Pow(15000,2)/(vessel.transform.position-origin).sqrMagnitude; - - if(vessel.Landed) - { - sig *= 0.25f; - } - if(vessel.Splashed) - { - sig *= 0.4f; - } - - //notching and ground clutter - Vector3 targetDirection = (vessel.transform.position-origin).normalized; - Vector3 targetClosureV = Vector3.ProjectOnPlane(Vector3.Project(vessel.srf_velocity,targetDirection), upVector); - float notchFactor = 1; - float angleFromUp = Vector3.Angle(targetDirection,upVector); - float lookDownAngle = angleFromUp-90; - - if(lookDownAngle > 5) - { - notchFactor = Mathf.Clamp(targetClosureV.sqrMagnitude / 3600f, 0.1f, 1f); - } - else - { - notchFactor = Mathf.Clamp(targetClosureV.sqrMagnitude / 3600f, 0.8f, 3f); - } - - float groundClutterFactor = Mathf.Clamp((90/angleFromUp), 0.25f, 1.85f); - sig *= groundClutterFactor; - sig *= notchFactor; - - var vci = vessel.GetComponent(); - if(vci) sig *= vci.GetChaffMultiplier(); - - - /* - if(Mathf.Round(Time.time)%2 == 0) - { - Debug.Log ("================================"); - Debug.Log ("targetAxV: "+targetClosureV.magnitude); - Debug.Log ("lookdownAngle: "+lookDownAngle); - Debug.Log ("notchFactor: "+notchFactor); - Debug.Log ("groundClutterFactor: "+groundClutterFactor); - } - */ - - return sig; - } - - public static bool TerrainCheck(Vector3 start, Vector3 end) - { - return Physics.Linecast(start, end, 1<<15); - } - - - - - - public static Vector2 WorldToRadar(Vector3 worldPosition, Transform referenceTransform, Rect radarRect, float maxDistance) - { - float scale = maxDistance/(radarRect.height/2); - Vector3 localPosition = referenceTransform.InverseTransformPoint(worldPosition); - localPosition.y = 0; - Vector2 radarPos = new Vector2((radarRect.width/2)+(localPosition.x/scale), (radarRect.height/2)-(localPosition.z/scale)); - return radarPos; - } - - public static Vector2 WorldToRadarRadial(Vector3 worldPosition, Transform referenceTransform, Rect radarRect, float maxDistance, float maxAngle) - { - float scale = maxDistance/(radarRect.height); - Vector3 localPosition = referenceTransform.InverseTransformPoint(worldPosition); - localPosition.y = 0; - float angle = Vector3.Angle(localPosition, Vector3.forward); - if(localPosition.x < 0) angle = -angle; - float xPos = (radarRect.width/2) + ((angle/maxAngle)*radarRect.width/2); - float yPos = radarRect.height - (new Vector2 (localPosition.x, localPosition.z)).magnitude / scale; - Vector2 radarPos = new Vector2(xPos, yPos); - return radarPos; - } - - - - - - } -} - diff --git a/BahaTurret/RadarWarningReceiver.cs b/BahaTurret/RadarWarningReceiver.cs deleted file mode 100644 index 8ceabbb40..000000000 --- a/BahaTurret/RadarWarningReceiver.cs +++ /dev/null @@ -1,346 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -namespace BahaTurret -{ - - public class RadarWarningReceiver : PartModule - { - public delegate void RadarPing(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime); - public static event RadarPing OnRadarPing; - - public delegate void MissileLaunchWarning(Vector3 source, Vector3 direction); - public static event MissileLaunchWarning OnMissileLaunch; - - public enum RWRThreatTypes{SAM = 0, Fighter = 1, AWACS = 2, MissileLaunch = 3, MissileLock = 4, Detection = 5} - string[] iconLabels = new string[]{"S", "F", "A", "M", "M", "D"}; - - - public MissileFire weaponManager; - - [KSPField(isPersistant = true)] - public bool rwrEnabled = false; - - public static Texture2D rwrDiamondTexture = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "rwrDiamond", false); - public static Texture2D rwrMissileTexture = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "rwrMissileIcon", false); - public static AudioClip radarPingSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rwrPing"); - public static AudioClip missileLockSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rwrMissileLock"); - public static AudioClip missileLaunchSound = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/mLaunchWarning"); - - //float lastTimePinged = 0; - const float minPingInterval = 0.12f; - const float pingPersistTime = 1; - - const int dataCount = 10; - - public float rwrDisplayRange = 8000; - - public TargetSignatureData[] pingsData; - public Vector3[] pingWorldPositions; - List launchWarnings; - - Transform rt; - Transform referenceTransform - { - get - { - if(!rt) - { - rt = new GameObject().transform; - rt.parent = part.transform; - rt.localPosition = Vector3.zero; - } - return rt; - } - - } - - Rect displayRect = new Rect(0, 0, 256, 256); - - GUIStyle rwrIconLabelStyle; - - AudioSource audioSource; - public static Rect windowRect; - public static bool windowRectInitialized = false; - - - - public override void OnStart(StartState state) - { - if(HighLogic.LoadedSceneIsFlight) - { - - pingsData = new TargetSignatureData[dataCount]; - pingWorldPositions = new Vector3[dataCount]; - TargetSignatureData.ResetTSDArray(ref pingsData); - launchWarnings = new List(); - - rwrIconLabelStyle = new GUIStyle(); - rwrIconLabelStyle.alignment = TextAnchor.MiddleCenter; - rwrIconLabelStyle.normal.textColor = Color.green; - rwrIconLabelStyle.fontSize = 12; - rwrIconLabelStyle.border = new RectOffset(0,0,0,0); - rwrIconLabelStyle.clipping = TextClipping.Overflow; - rwrIconLabelStyle.wordWrap = false; - rwrIconLabelStyle.fontStyle = FontStyle.Bold; - - audioSource = gameObject.AddComponent(); - audioSource.minDistance = 500; - audioSource.maxDistance = 1000; - audioSource.spatialBlend = 1; - audioSource.dopplerLevel = 0; - audioSource.loop = false; - - UpdateVolume(); - BDArmorySettings.OnVolumeChange += UpdateVolume; - - float size = displayRect.height + 20; - if(!windowRectInitialized) - { - windowRect = new Rect(40, Screen.height - size - 20, size, size+20); - windowRectInitialized = true; - } - - foreach(var mf in vessel.FindPartModulesImplementing()) - { - mf.rwr = this; - if(!weaponManager) - { - weaponManager = mf; - } - } - - if(rwrEnabled) - { - EnableRWR(); - } - } - } - - void UpdateVolume() - { - if(audioSource) - { - audioSource.volume = BDArmorySettings.BDARMORY_UI_VOLUME; - } - } - - public void EnableRWR() - { - OnRadarPing += ReceivePing; - OnMissileLaunch += ReceiveLaunchWarning; - rwrEnabled = true; - } - - public void DisableRWR() - { - OnRadarPing -= ReceivePing; - OnMissileLaunch -= ReceiveLaunchWarning; - rwrEnabled = false; - } - - void OnDestroy() - { - OnRadarPing -= ReceivePing; - OnMissileLaunch -= ReceiveLaunchWarning; - BDArmorySettings.OnVolumeChange -= UpdateVolume; - } - - - IEnumerator PingLifeRoutine(int index, float lifeTime) - { - yield return new WaitForSeconds(Mathf.Clamp(lifeTime-0.04f, minPingInterval, lifeTime)); - pingsData[index] = TargetSignatureData.noTarget; - } - - IEnumerator LaunchWarningRoutine(TargetSignatureData data) - { - launchWarnings.Add(data); - yield return new WaitForSeconds(2); - launchWarnings.Remove(data); - } - - void ReceiveLaunchWarning(Vector3 source, Vector3 direction) - { - if(!referenceTransform || !part) return; - - float sqrDist = (part.transform.position - source).sqrMagnitude; - if(sqrDist < Mathf.Pow(5000, 2) && sqrDist > Mathf.Pow(100,2) && Vector3.Angle(direction, part.transform.position - source) < 15) - { - StartCoroutine(LaunchWarningRoutine(new TargetSignatureData(Vector3.zero, RadarUtils.WorldToRadar(source, referenceTransform, displayRect, rwrDisplayRange), Vector3.zero, true, (float)RWRThreatTypes.MissileLaunch))); - PlayWarningSound(RWRThreatTypes.MissileLaunch); - - if(weaponManager && weaponManager.guardMode) - { - weaponManager.FireAllCountermeasures(UnityEngine.Random.Range(2,4)); - weaponManager.incomingThreatPosition = source; - } - } - } - - void ReceivePing(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime) - { - if(rwrEnabled && vessel && v == vessel) - { - if(type == RWRThreatTypes.MissileLaunch) - { - StartCoroutine(LaunchWarningRoutine(new TargetSignatureData(Vector3.zero, RadarUtils.WorldToRadar(source, referenceTransform, displayRect, rwrDisplayRange), Vector3.zero, true, (float)type))); - PlayWarningSound(type); - return; - } - else if(type == RWRThreatTypes.MissileLock) - { - if(!BDArmorySettings.ALLOW_LEGACY_TARGETING && weaponManager && weaponManager.guardMode) - { - weaponManager.FireChaff(); - } - } - - int openIndex = -1; - for(int i = 0; i < dataCount; i++) - { - if(pingsData[i].exists && ((Vector2)pingsData[i].position - RadarUtils.WorldToRadar(source, referenceTransform, displayRect, rwrDisplayRange)).sqrMagnitude < Mathf.Pow(20, 2)) - { - break; - } - - if(!pingsData[i].exists && openIndex == -1) - { - openIndex = i; - } - } - - if(openIndex >= 0) - { - referenceTransform.rotation = Quaternion.LookRotation(vessel.ReferenceTransform.up, VectorUtils.GetUpDirection(transform.position)); - - pingsData[openIndex] = new TargetSignatureData(Vector3.zero, RadarUtils.WorldToRadar(source, referenceTransform, displayRect, rwrDisplayRange), Vector3.zero, true, (float)type); - pingWorldPositions[openIndex] = source; - StartCoroutine(PingLifeRoutine(openIndex, persistTime)); - - PlayWarningSound(type); - } - } - } - - void PlayWarningSound(RWRThreatTypes type) - { - if(vessel.isActiveVessel) - { - switch(type) - { - case RWRThreatTypes.MissileLaunch: - audioSource.Stop(); - audioSource.clip = missileLaunchSound; - audioSource.Play(); - break; - case RWRThreatTypes.MissileLock: - if(audioSource.clip == missileLaunchSound && audioSource.isPlaying) break; - audioSource.Stop(); - audioSource.clip = (missileLockSound); - audioSource.Play(); - break; - default: - if(!audioSource.isPlaying) - { - audioSource.clip = (radarPingSound); - audioSource.Play(); - } - break; - } - } - } - - - void OnGUI() - { - if(HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && BDArmorySettings.GAME_UI_ENABLED && vessel.isActiveVessel && rwrEnabled) - { - windowRect = GUI.Window(94353, windowRect, RWRWindow, "Radar Warning Receiver", HighLogic.Skin.window); - BDGUIUtils.UseMouseEventInRect(windowRect); - } - } - - void RWRWindow(int windowID) - { - GUI.DragWindow(new Rect(0,0,windowRect.width-18, 30)); - if(GUI.Button(new Rect(windowRect.width - 28, 2, 26, 26), "X", HighLogic.Skin.button)) - { - DisableRWR(); - } - GUI.BeginGroup(new Rect(10, 30, displayRect.width, displayRect.height)); - GUI.DragWindow(displayRect); - - GUI.DrawTexture(displayRect, VesselRadarData.omniBgTexture, ScaleMode.StretchToFill, false); - float pingSize = 32; - - for(int i = 0; i < dataCount; i++) - { - Vector2 pingPosition = (Vector2)pingsData[i].position; - pingPosition = Vector2.MoveTowards(displayRect.center, pingPosition, displayRect.center.x - (pingSize / 2)); - Rect pingRect = new Rect(pingPosition.x - (pingSize / 2), pingPosition.y - (pingSize / 2), pingSize, pingSize); - if(pingsData[i].exists) - { - if(pingsData[i].signalStrength == 4) - { - GUI.DrawTexture(pingRect, rwrMissileTexture, ScaleMode.StretchToFill, true); - } - else - { - GUI.DrawTexture(pingRect, rwrDiamondTexture, ScaleMode.StretchToFill, true); - GUI.Label(pingRect, iconLabels[Mathf.RoundToInt(pingsData[i].signalStrength)], rwrIconLabelStyle); - } - } - } - - foreach(var lw in launchWarnings) - { - Vector2 pingPosition = (Vector2)lw.position; - pingPosition = Vector2.MoveTowards(displayRect.center, pingPosition, displayRect.center.x - (pingSize / 2)); - - Rect pingRect = new Rect(pingPosition.x - (pingSize / 2), pingPosition.y - (pingSize / 2), pingSize, pingSize); - GUI.DrawTexture(pingRect, rwrMissileTexture, ScaleMode.StretchToFill, true); - } - - GUI.EndGroup(); - - - - } - - - - public static void PingRWR(Vessel v, Vector3 source, RWRThreatTypes type, float persistTime) - { - if(OnRadarPing != null) - { - OnRadarPing(v, source, type, persistTime); - } - } - - public static void PingRWR(Ray ray, float fov, RWRThreatTypes type, float persistTime) - { - foreach(var vessel in FlightGlobals.Vessels) - { - if(vessel.loaded) - { - Vector3 dirToVessel = vessel.transform.position - ray.origin; - if(Vector3.Angle(ray.direction, dirToVessel) < fov / 2) - { - PingRWR(vessel, ray.origin, type, persistTime); - } - } - } - } - - public static void WarnMissileLaunch(Vector3 source, Vector3 direction) - { - if(OnMissileLaunch != null) - { - OnMissileLaunch(source, direction); - } - } - } -} - diff --git a/BahaTurret/RippleOption.cs b/BahaTurret/RippleOption.cs deleted file mode 100644 index d9c4ad043..000000000 --- a/BahaTurret/RippleOption.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace BahaTurret -{ - public class RippleOption - { - public bool rippleFire; - public float rpm; - public RippleOption(bool rippleFire, float rpm) - { - this.rippleFire = rippleFire; - this.rpm = rpm; - } - } -} - diff --git a/BahaTurret/RocketLauncher.cs b/BahaTurret/RocketLauncher.cs deleted file mode 100644 index 6079fd7d8..000000000 --- a/BahaTurret/RocketLauncher.cs +++ /dev/null @@ -1,1023 +0,0 @@ -using System; -using UnityEngine; -using System.Collections; -using System.Collections.Generic; - -namespace BahaTurret -{ - public class RocketLauncher : PartModule, IBDWeapon - { - public bool hasRocket = true; - - [KSPField] - public string shortName = string.Empty; - - [KSPField(isPersistant = false)] - public string rocketType; - - [KSPField(isPersistant = false)] - public string rocketModelPath; - - - - [KSPField(isPersistant = false)] - public float rocketMass; - - [KSPField(isPersistant = false)] - public float thrust; - - [KSPField(isPersistant = false)] - public float thrustTime; - - [KSPField(isPersistant = false)] - public float blastRadius; - - [KSPField(isPersistant = false)] - public float blastForce; - - [KSPField] - public float blastHeat = -1; - - [KSPField(isPersistant = false)] - public bool descendingOrder = true; - - [KSPField(isPersistant = false)] - public string explModelPath = "BDArmory/Models/explosion/explosion"; - - - [KSPField(isPersistant = false)] - public string explSoundPath = "BDArmory/Sounds/explode1"; - - [KSPField] - public float thrustDeviation = 0.10f; - - [KSPField] - public float maxTargetingRange = 8000; - float currentTgtRange = 8000; - float predictedFlightTime = 1; - - public bool drawAimer = false; - - Vector3 rocketPrediction = Vector3.zero; - Texture2D aimerTexture; - - Transform[] rockets; - - AudioSource sfAudioSource; - - //animation - [KSPField] - public string deployAnimationName; - [KSPField] - public float deployAnimationSpeed = 1; - AnimationState deployAnimState; - bool hasDeployAnimation = false; - public bool deployed = false; - Coroutine deployAnimRoutine; - - public bool readyToFire = true; - - public Vessel legacyGuardTarget = null; - public float lastAutoFiredTime = 0; - public float autoRippleRate = 0; - public float autoFireStartTime = 0; - public float autoFireDuration = 0; - - //turret - [KSPField] - public int turretID = 0; - public ModuleTurret turret; - Vector3 trajectoryOffset = Vector3.zero; - public MissileFire weaponManager; - bool targetInTurretView = true; - public float yawRange - { - get - { - return turret ? turret.yawRange : 0; - } - } - public float maxPitch - { - get - { - return turret ? turret.maxPitch : 0; - } - } - public float minPitch - { - get - { - return turret ? turret.minPitch : 0; - } - } - - double lastRocketsLeft = 0; - - //weapon interface - public Part GetPart() - { - return part; - } - public string GetShortName() - { - return shortName; - } - public WeaponClasses GetWeaponClass() - { - return WeaponClasses.Rocket; - } - public string GetSubLabel() - { - return string.Empty; - } - - - - [KSPAction("Fire")] - public void AGFire(KSPActionParam param) - { - FireRocket(); - } - - [KSPEvent(guiActive = true, guiName = "Fire", active = true)] - public void GuiFire() - { - FireRocket(); - } - - [KSPEvent(guiActive = true, guiName = "Jettison", active = true, guiActiveEditor = false)] - public void Jettison() - { - if(turret) - { - return; - } - - part.decouple(0); - if(BDArmorySettings.Instance.ActiveWeaponManager!=null) BDArmorySettings.Instance.ActiveWeaponManager.UpdateList(); - } - - [KSPEvent(guiActive = false, guiName = "Toggle Turret", guiActiveEditor = false)] - public void ToggleTurret() - { - if(deployed) - { - DisableTurret(); - } - else - { - EnableTurret(); - } - } - - public void EnableTurret() - { - deployed = true; - drawAimer = true; - hasReturned = false; - - if(returnRoutine != null) - { - StopCoroutine(returnRoutine); - returnRoutine = null; - } - - if(hasDeployAnimation) - { - if(deployAnimRoutine != null) - { - StopCoroutine(deployAnimRoutine); - } - deployAnimRoutine = StartCoroutine(DeployAnimRoutine(true)); - } - else - { - readyToFire = true; - } - - } - - public void DisableTurret() - { - deployed = false; - readyToFire = false; - drawAimer = false; - hasReturned = false; - targetInTurretView = false; - - if(returnRoutine != null) - { - StopCoroutine(returnRoutine); - } - returnRoutine = StartCoroutine(ReturnRoutine()); - - if(hasDeployAnimation) - { - if(deployAnimRoutine != null) - { - StopCoroutine(deployAnimRoutine); - } - - deployAnimRoutine = StartCoroutine(DeployAnimRoutine(false)); - } - - } - - bool hasReturned = true; - Coroutine returnRoutine; - IEnumerator ReturnRoutine() - { - if(deployed) - { - hasReturned = false; - yield break; - } - - yield return new WaitForSeconds(0.25f); - - while(!turret.ReturnTurret()) - { - yield return new WaitForFixedUpdate(); - } - - hasReturned = true; - - } - - - public override void OnStart (PartModule.StartState state) - { - if(HighLogic.LoadedSceneIsFlight) - { - part.force_activate(); - - aimerTexture = BDArmorySettings.Instance.greenPointCircleTexture;// GameDatabase.Instance.GetTexture("BDArmory/Textures/grayCircle", false); - - sfAudioSource = gameObject.AddComponent(); - sfAudioSource.minDistance = 1; - sfAudioSource.maxDistance = 2000; - sfAudioSource.dopplerLevel = 0; - sfAudioSource.priority = 230; - sfAudioSource.spatialBlend = 1; - - MakeRocketArray(); - UpdateRocketScales(); - - if (shortName == string.Empty) - { - shortName = part.partInfo.title; - } - - UpdateAudio(); - BDArmorySettings.OnVolumeChange += UpdateAudio; - - - } - - if(HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor) - { - foreach(var turr in part.FindModulesImplementing()) - { - if(turr.turretID == turretID) - { - turret = turr; - targetInTurretView = false; - break; - } - } - - if(turret) - { - Events["GuiFire"].guiActive = false; - Events["Jettison"].guiActive = false; - Actions["AGFire"].active = false; - - if(HighLogic.LoadedSceneIsFlight) - { - Events["ToggleTurret"].guiActive = true; - } - } - - if(!string.IsNullOrEmpty(deployAnimationName)) - { - deployAnimState = Misc.SetUpSingleAnimation(deployAnimationName, part); - hasDeployAnimation = true; - - readyToFire = false; - } - } - } - - IEnumerator DeployAnimRoutine(bool forward) - { - readyToFire = false; - BDArmorySettings.Instance.UpdateCursorState(); - - if(forward) - { - while(deployAnimState.normalizedTime < 1) - { - deployAnimState.speed = deployAnimationSpeed; - yield return null; - } - - deployAnimState.normalizedTime = 1; - } - else - { - while(!hasReturned) - { - deployAnimState.speed = 0; - yield return null; - } - - while(deployAnimState.normalizedTime > 0) - { - deployAnimState.speed = -deployAnimationSpeed; - yield return null; - } - - deployAnimState.normalizedTime = 0; - } - - deployAnimState.speed = 0; - - readyToFire = deployed; - BDArmorySettings.Instance.UpdateCursorState(); - } - - void UpdateAudio() - { - if(sfAudioSource) - { - sfAudioSource.volume = BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - } - } - - void OnDestroy() - { - BDArmorySettings.OnVolumeChange -= UpdateAudio; - } - - - - public override void OnFixedUpdate () - { - if(GetRocketResource().amount != lastRocketsLeft) - { - UpdateRocketScales(); - lastRocketsLeft = GetRocketResource().amount; - } - - if(!vessel.IsControllable) - { - return; - } - - SimulateTrajectory(); - - currentTgtRange = maxTargetingRange; - - if(deployed && readyToFire && turret) - { - Aim(); - } - } - - public override void OnUpdate() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(readyToFire && deployed) - { - if(returnRoutine != null) - { - StopCoroutine(returnRoutine); - returnRoutine = null; - } - - if(weaponManager && weaponManager.guardMode && weaponManager.selectedWeaponString == GetShortName()) - { - if(Time.time - autoFireStartTime < autoFireDuration) - { - float fireInterval = 0.5f; - if(autoRippleRate > 0) fireInterval = 60f / autoRippleRate; - if(Time.time - lastAutoFiredTime > fireInterval) - { - FireRocket(); - lastAutoFiredTime = Time.time; - } - } - } - else if((!weaponManager || (weaponManager.selectedWeaponString != GetShortName() && !weaponManager.guardMode))) - { - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.WEAP_FIRE_KEY) && (vessel.isActiveVessel || BDArmorySettings.REMOTE_SHOOTING)) - { - FireRocket(); - } - } - } - } - } - - bool mouseAiming = false; - void Aim() - { - mouseAiming = false; - if(weaponManager && (weaponManager.slavingTurrets || weaponManager.guardMode)) - { - SlavedAim(); - } - else - { - if(vessel.isActiveVessel || BDArmorySettings.REMOTE_SHOOTING) - { - MouseAim(); - } - } - } - - void SlavedAim() - { - Vector3 targetPosition; - Vector3 targetVel; - Vector3 targetAccel; - if(weaponManager.slavingTurrets) - { - targetPosition = weaponManager.slavedPosition; - targetVel = weaponManager.slavedVelocity; - targetAccel = weaponManager.slavedAcceleration; - - //targetPosition -= vessel.srf_velocity * predictedFlightTime; - } - else if(legacyGuardTarget) - { - targetPosition = legacyGuardTarget.CoM; - targetVel = legacyGuardTarget.srf_velocity; - targetAccel = legacyGuardTarget.acceleration; - } - else - { - targetInTurretView = false; - return; - } - - currentTgtRange = Vector3.Distance(targetPosition, rockets[0].parent.transform.position); - - - targetPosition += trajectoryOffset; - targetPosition += targetVel * predictedFlightTime; - targetPosition += 0.5f * targetAccel * predictedFlightTime * predictedFlightTime; - - turret.AimToTarget(targetPosition); - targetInTurretView = turret.TargetInRange(targetPosition, 2, maxTargetingRange); - } - - void MouseAim() - { - mouseAiming = true; - Vector3 targetPosition; - // float maxTargetingRange = 8000; - - float targetDistance; - - //MouseControl - Vector3 mouseAim = new Vector3(Input.mousePosition.x/Screen.width, Input.mousePosition.y/Screen.height, 0); - Ray ray = FlightCamera.fetch.mainCamera.ViewportPointToRay(mouseAim); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, maxTargetingRange, 557057)) - { - targetPosition = hit.point; - - //aim through self vessel if occluding mouseray - Part p = hit.collider.gameObject.GetComponentInParent(); - if(p && p.vessel && p.vessel == vessel) - { - targetPosition = ray.direction * maxTargetingRange + FlightCamera.fetch.mainCamera.transform.position; - } - - targetDistance = Vector3.Distance(hit.point, rockets[0].parent.position); - } - else - { - targetPosition = (ray.direction * (maxTargetingRange+(FlightCamera.fetch.Distance*0.75f))) + FlightCamera.fetch.mainCamera.transform.position; - targetDistance = maxTargetingRange; - } - - currentTgtRange = targetDistance; - - /* - float accelDistance = (thrust / rocketMass) * ((thrustTime * thrustTime) / 2); - float finalV = (thrust / rocketMass) * thrustTime; - float aveThrustV = finalV / 2; - float flightTime = targetDistance / finalV;//(accelDistance / aveThrustV) + ((targetDistance - accelDistance) / finalV); - float gravDrop = 0.5f * (float)FlightGlobals.getGeeForceAtPosition(part.transform.position).magnitude * flightTime * flightTime; - targetPosition += gravDrop * VectorUtils.GetUpDirection(part.transform.position); - */ - - targetPosition += trajectoryOffset; - - - turret.AimToTarget(targetPosition); - targetInTurretView = turret.TargetInRange(targetPosition, 2, maxTargetingRange); - } - - public void FireRocket() - { - if(!readyToFire) return; - if(!targetInTurretView) return; - - PartResource rocketResource = GetRocketResource(); - - if(rocketResource == null) - { - Debug.Log (part.name +" doesn't carry the rocket resource it was meant to"); - return; - } - - int rocketsLeft = (int) Math.Floor(rocketResource.amount); - - if(rocketsLeft >= 1) - { - Transform currentRocketTfm = rockets[rocketsLeft-1]; - - GameObject rocketObj = GameDatabase.Instance.GetModel(rocketModelPath); - rocketObj = (GameObject) Instantiate(rocketObj, currentRocketTfm.position, currentRocketTfm.parent.rotation); - rocketObj.transform.rotation = currentRocketTfm.parent.rotation; - rocketObj.transform.localScale = part.rescaleFactor * Vector3.one; - currentRocketTfm.localScale = Vector3.zero; - Rocket rocket = rocketObj.AddComponent(); - rocket.explModelPath = explModelPath; - rocket.explSoundPath = explSoundPath; - rocket.spawnTransform = currentRocketTfm; - rocket.mass = rocketMass; - rocket.blastForce = blastForce; - rocket.blastHeat = blastHeat; - rocket.blastRadius = blastRadius; - rocket.thrust = thrust; - rocket.thrustTime = thrustTime; - rocket.randomThrustDeviation = thrustDeviation; - if(BDArmorySettings.ALLOW_LEGACY_TARGETING && vessel.targetObject != null) - { - rocket.targetVessel = vessel.targetObject.GetVessel(); - } - - rocket.sourceVessel = vessel; - rocketObj.SetActive(true); - rocketObj.transform.SetParent(currentRocketTfm.parent); - rocket.parentRB = part.rb; - - sfAudioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/launch")); - rocketResource.amount--; - - lastRocketsLeft = rocketResource.amount; - } - } - - - void SimulateTrajectory() - { - if((BDArmorySettings.AIM_ASSIST && BDArmorySettings.DRAW_AIMERS && drawAimer && vessel.isActiveVessel) || (weaponManager && weaponManager.guardMode && weaponManager.selectedWeaponString==GetShortName())) - { - float simTime = 0; - Transform fireTransform = rockets[0].parent; - Vector3 pointingDirection = fireTransform.forward; - Vector3 simVelocity = part.rb.velocity; - Vector3 simCurrPos = fireTransform.position + (part.rb.velocity*Time.fixedDeltaTime); - Vector3 simPrevPos = fireTransform.position + (part.rb.velocity*Time.fixedDeltaTime); - Vector3 simStartPos = fireTransform.position + (part.rb.velocity*Time.fixedDeltaTime); - bool simulating = true; - float simDeltaTime = 0.02f; - List pointPositions = new List(); - pointPositions.Add(simCurrPos); - - bool slaved = turret && weaponManager && (weaponManager.slavingTurrets || weaponManager.guardMode); - float atmosMultiplier = Mathf.Clamp01(2.5f*(float)FlightGlobals.getAtmDensity(vessel.staticPressurekPa, vessel.externalTemperature, vessel.mainBody)); - while(simulating) - { - RaycastHit hit; - - if(simTime > thrustTime) - { - simDeltaTime = 0.1f; - } - - if(simTime > 0.04f) - { - simDeltaTime = 0.02f; - if(simTime < thrustTime) - { - simVelocity += thrust / rocketMass * simDeltaTime * pointingDirection; - } - - //rotation (aero stabilize) - pointingDirection = Vector3.RotateTowards(pointingDirection, simVelocity+Krakensbane.GetFrameVelocity(), atmosMultiplier * (0.5f * (simTime)) * 50 * simDeltaTime * Mathf.Deg2Rad, 0); - } - - //gravity - simVelocity += FlightGlobals.getGeeForceAtPosition(simCurrPos) * simDeltaTime; - - simCurrPos += simVelocity * simDeltaTime; - pointPositions.Add(simCurrPos); - if(!mouseAiming && !slaved) - { - if(simTime > 0.1f && Physics.Raycast(simPrevPos, simCurrPos - simPrevPos, out hit, Vector3.Distance(simPrevPos, simCurrPos), 557057)) - { - rocketPrediction = hit.point; - simulating = false; - break; - } - else if(FlightGlobals.getAltitudeAtPos(simCurrPos) < 0) - { - rocketPrediction = simCurrPos; - simulating = false; - break; - } - } - - - - simPrevPos = simCurrPos; - - if((simStartPos-simCurrPos).sqrMagnitude>currentTgtRange*currentTgtRange) - { - rocketPrediction = simStartPos + (simCurrPos-simStartPos).normalized*currentTgtRange; - //rocketPrediction = simCurrPos; - simulating = false; - } - simTime += simDeltaTime; - } - - Vector3 pointingPos = fireTransform.position + (fireTransform.forward * currentTgtRange); - trajectoryOffset = pointingPos - rocketPrediction; - predictedFlightTime = simTime; - - if(BDArmorySettings.DRAW_DEBUG_LINES && BDArmorySettings.DRAW_AIMERS) - { - Vector3[] pointsArray = pointPositions.ToArray(); - if(gameObject.GetComponent()==null) - { - LineRenderer lr = gameObject.AddComponent(); - lr.SetWidth(.1f, .1f); - lr.SetVertexCount(pointsArray.Length); - for(int i = 0; i(); - lr.enabled = true; - lr.SetVertexCount(pointsArray.Length); - for(int i = 0; i()!=null) - { - gameObject.GetComponent().enabled = false; - } - } - } - - //for straight aimer - else if(BDArmorySettings.DRAW_AIMERS && drawAimer && vessel.isActiveVessel) - { - RaycastHit hit; - float distance = 2500; - if(Physics.Raycast(transform.position,transform.forward, out hit, distance, 557057)) - { - rocketPrediction = hit.point; - } - else - { - rocketPrediction = transform.position+(transform.forward*distance); - } - } - - } - - void OnGUI() - { - if(drawAimer && vessel.isActiveVessel && BDArmorySettings.DRAW_AIMERS && !MapView.MapIsEnabled) - { - float size = 30; - - Vector3 aimPosition = FlightCamera.fetch.mainCamera.WorldToViewportPoint(rocketPrediction); - - Rect drawRect = new Rect(aimPosition.x*Screen.width-(0.5f*size), (1-aimPosition.y)*Screen.height-(0.5f*size), size, size); - float cameraAngle = Vector3.Angle(FlightCamera.fetch.GetCameraTransform().forward, rocketPrediction-FlightCamera.fetch.mainCamera.transform.position); - if(cameraAngle<90) GUI.DrawTexture(drawRect, aimerTexture); - - } - - } - - void MakeRocketArray() - { - Transform rocketsTransform = part.FindModelTransform("rockets"); - int numOfRockets = rocketsTransform.childCount; - rockets = new Transform[numOfRockets]; - - for(int i = 0; i < numOfRockets; i++) - { - string rocketName = rocketsTransform.GetChild(i).name; - int rocketIndex = int.Parse(rocketName.Substring(7))-1; - rockets[rocketIndex] = rocketsTransform.GetChild(i); - } - - if(!descendingOrder) Array.Reverse(rockets); - } - - - public PartResource GetRocketResource() - { - foreach(var res in part.Resources.list) - { - if(res.resourceName == rocketType) return res; - } - - return null; - - } - - void UpdateRocketScales() - { - PartResource rocketResource = GetRocketResource(); - double rocketsLeft = Math.Floor(rocketResource.amount); - double rocketsMax = rocketResource.maxAmount; - for(int i = 0; i (); - pEmitters = gameObject.GetComponentsInChildren(); - - foreach(var pe in pEmitters) - { - if(FlightGlobals.getStaticPressure(transform.position)==0 && pe.useWorldSpace) - { - pe.emit = false; - } - else if(pe.useWorldSpace) - { - BDAGaplessParticleEmitter gpe = pe.gameObject.AddComponent(); - gpe.rb = rb; - gpe.emit = true; - } - } - - prevPosition = transform.position; - currPosition = transform.position; - startTime = Time.time; - - rb.mass = mass; - rb.isKinematic = true; - //rigidbody.velocity = startVelocity; - if(!FlightGlobals.RefFrameIsRotating) rb.useGravity = false; - - audioSource = gameObject.AddComponent(); - audioSource.loop = true; - audioSource.minDistance = 1; - audioSource.maxDistance = 2000; - audioSource.dopplerLevel = 0.5f; - audioSource.volume = 0.9f * BDArmorySettings.BDARMORY_WEAPONS_VOLUME; - audioSource.pitch = 1.4f; - audioSource.clip = GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/rocketLoop"); - - rb.useGravity = false; - - randThrustSeed = UnityEngine.Random.Range(0f, 100f); - } - - void FixedUpdate() - { - //floatingOrigin fix - if(sourceVessel!=null && (transform.position-sourceVessel.transform.position-relativePos).sqrMagnitude > 800*800) - { - transform.position = sourceVessel.transform.position+relativePos + (rb.velocity * Time.fixedDeltaTime); - } - if(sourceVessel!=null) relativePos = transform.position-sourceVessel.transform.position; - // - - - if(Time.time - startTime < stayTime && transform.parent!=null) - { - transform.rotation = transform.parent.rotation; - transform.position = spawnTransform.position;//+(transform.parent.rigidbody.velocity*Time.fixedDeltaTime); - } - else - { - if(transform.parent != null && parentRB) - { - startVelocity = parentRB.velocity; - transform.parent = null; - rb.isKinematic = false; - rb.velocity = startVelocity; - } - } - - if(rb && !rb.isKinematic) - { - //physics - if(FlightGlobals.RefFrameIsRotating) - { - rb.velocity += FlightGlobals.getGeeForceAtPosition(transform.position) * Time.fixedDeltaTime; - } - - //guidance and attitude stabilisation scales to atmospheric density. - float atmosMultiplier = Mathf.Clamp01 (2.5f*(float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody)); - - //model transform. always points prograde - transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(rb.velocity+Krakensbane.GetFrameVelocity(), transform.up), atmosMultiplier * (0.5f*(Time.time-startTime)) * 50*Time.fixedDeltaTime); - - - if(Time.time - startTime < thrustTime && Time.time-startTime > stayTime) - { - float random = randomThrustDeviation * (1-(Mathf.PerlinNoise(4*Time.time, randThrustSeed)*2)); - float random2 = randomThrustDeviation * (1-(Mathf.PerlinNoise(randThrustSeed, 4*Time.time)*2)); - rb.AddRelativeForce(new Vector3(random,random2,thrust)); - } - - } - - - - - - - - if(Time.time - startTime > thrustTime) - { - //isThrusting = false; - foreach(var pEmitter in pEmitters) - { - if(pEmitter.useWorldSpace) - { - pEmitter.minSize = Mathf.MoveTowards(pEmitter.minSize, 0.1f, 0.05f); - pEmitter.maxSize = Mathf.MoveTowards(pEmitter.maxSize, 0.2f, 0.05f); - } - else - { - pEmitter.minSize = Mathf.MoveTowards(pEmitter.minSize, 0, 0.1f); - pEmitter.maxSize = Mathf.MoveTowards(pEmitter.maxSize, 0, 0.1f); - if(pEmitter.maxSize == 0) - { - pEmitter.emit = false; - - } - } - - } - } - - if(Time.time - startTime > 0.1f+stayTime) - { - //audioSource.pitch = SoundUtil.getDopplerPitchFactor(rigidbody.velocity, transform.position)*1.4f; - currPosition = transform.position; - float dist = (currPosition-prevPosition).magnitude; - Ray ray = new Ray(prevPosition, currPosition-prevPosition); - RaycastHit hit; - if(Physics.Raycast(ray, out hit, dist, 557057)) - { - - Part hitPart = null; - try{ - hitPart = Part.FromGO(hit.rigidbody.gameObject); - }catch(NullReferenceException){} - - - if(hitPart==null || (hitPart!=null && hitPart.vessel!=sourceVessel)) - { - Detonate(hit.point); - } - } - else if(FlightGlobals.getAltitudeAtPos(transform.position)<0) - { - Detonate(transform.position); - } - } - else if(FlightGlobals.getAltitudeAtPos(currPosition)<=0) - { - Detonate(currPosition); - } - prevPosition = currPosition; - - if(Time.time - startTime > lifeTime) - { - Detonate (transform.position); - } - - //proxy detonation - if(targetVessel!=null && (transform.position-targetVessel.transform.position).sqrMagnitude < 0.5f*blastRadius*blastRadius) - { - Detonate(transform.position); - } - - } - - void Update() - { - if(HighLogic.LoadedSceneIsFlight) - { - if(BDArmorySettings.GameIsPaused) - { - if(audioSource.isPlaying) - { - audioSource.Stop(); - } - } - else - { - if(!audioSource.isPlaying) - { - audioSource.Play(); - } - } - } - } - - void Detonate(Vector3 pos) - { - BDArmorySettings.numberOfParticleEmitters--; - - ExplosionFX.CreateExplosion(pos, blastRadius, blastForce, blastHeat, sourceVessel, rb.velocity.normalized, explModelPath, explSoundPath); - - foreach(var emitter in pEmitters) - { - if(emitter.useWorldSpace) - { - emitter.gameObject.AddComponent(); - emitter.transform.parent = null; - } - } - - GameObject.Destroy(gameObject); //destroy rocket on collision - } - - - - - - - - } -} - diff --git a/BahaTurret/SeismicChargeFX.cs b/BahaTurret/SeismicChargeFX.cs deleted file mode 100644 index 98825253c..000000000 --- a/BahaTurret/SeismicChargeFX.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class SeismicChargeFX : MonoBehaviour - { - - AudioSource audioSource; - - - public static float originalShipVolume; - public static float originalMusicVolume; - public static float originalAmbienceVolume; - - - float startTime; - - Transform lightFlare; - - Rigidbody rb; - - void Start() - { - transform.localScale = 2 * Vector3.one; - lightFlare = gameObject.transform.FindChild("lightFlare"); - - - startTime = Time.time; - - audioSource = gameObject.AddComponent(); - audioSource.minDistance = 5000; - audioSource.maxDistance = 5000; - audioSource.dopplerLevel = 0f; - audioSource.pitch = UnityEngine.Random.Range(0.93f, 1f); - audioSource.volume = Mathf.Sqrt(originalShipVolume); - - audioSource.PlayOneShot(GameDatabase.Instance.GetAudioClip("BDArmory/Sounds/seismicCharge")); - - rb = gameObject.AddComponent(); - rb.useGravity = false; - rb.velocity = Vector3.zero; - - } - - void FixedUpdate() - { - lightFlare.LookAt(FlightCamera.fetch.mainCamera.transform.position, FlightCamera.fetch.mainCamera.transform.up); - - if(Time.time-startTime < 1.25f) - { - // - GameSettings.SHIP_VOLUME = Mathf.MoveTowards(GameSettings.SHIP_VOLUME, 0, originalShipVolume/0.7f); - GameSettings.MUSIC_VOLUME = Mathf.MoveTowards(GameSettings.MUSIC_VOLUME, 0, originalShipVolume/0.7f); - GameSettings.AMBIENCE_VOLUME = Mathf.MoveTowards(GameSettings.AMBIENCE_VOLUME, 0, originalShipVolume/0.7f); - } - else if(Time.time-startTime < 7.35f/audioSource.pitch) - { - //make it fade in more slowly - GameSettings.SHIP_VOLUME = Mathf.MoveTowards(GameSettings.SHIP_VOLUME, originalShipVolume, originalShipVolume/3f * Time.fixedDeltaTime); - GameSettings.MUSIC_VOLUME = Mathf.MoveTowards(GameSettings.MUSIC_VOLUME, originalMusicVolume, originalMusicVolume/3f * Time.fixedDeltaTime); - GameSettings.AMBIENCE_VOLUME = Mathf.MoveTowards(GameSettings.AMBIENCE_VOLUME, originalAmbienceVolume, originalAmbienceVolume/3f * Time.fixedDeltaTime); - - } - else - { - Destroy(gameObject); - } - } - - - void OnTriggerEnter(Collider other) - { - //hitting parts - Part explodePart = null; - try - { - explodePart = other.gameObject.GetComponentUpwards(); - explodePart.Unpack(); - }catch(NullReferenceException){} - - if(explodePart!=null) - { - explodePart.temperature = explodePart.maxTemp + 500; - } - else - { - //hitting buildings - DestructibleBuilding hitBuilding = null; - try{ - hitBuilding = other.gameObject.GetComponentUpwards(); - } - catch(NullReferenceException){} - if(hitBuilding!=null && hitBuilding.IsIntact) - { - hitBuilding.Demolish(); - } - } - } - - - - public static void CreateSeismicExplosion(Vector3 pos, Quaternion rot) - { - GameObject explosionModel = GameDatabase.Instance.GetModel("BDArmory/Models/seismicCharge/seismicExplosion"); - GameObject explosionObject = (GameObject) GameObject.Instantiate(explosionModel, pos, rot); - explosionObject.SetActive(true); - explosionObject.AddComponent(); - } - } -} - diff --git a/BahaTurret/ShellCasing.cs b/BahaTurret/ShellCasing.cs deleted file mode 100644 index 40e890874..000000000 --- a/BahaTurret/ShellCasing.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class ShellCasing : MonoBehaviour - { - public float startTime; - public Vector3 initialV; - - Vector3 velocity; - Vector3 angularVelocity; - - float atmDensity; - - void OnEnable() - { - startTime = Time.time; - velocity = initialV; - velocity += transform.rotation * new Vector3 (UnityEngine.Random.Range(-.1f,.1f), UnityEngine.Random.Range(-.1f,.1f), UnityEngine.Random.Range(6f,8f)); - angularVelocity = new Vector3(UnityEngine.Random.Range(-10f,10f),UnityEngine.Random.Range(-10f,10f),UnityEngine.Random.Range(-10f,10f)) * 10; - - atmDensity = (float)FlightGlobals.getAtmDensity(FlightGlobals.getStaticPressure(transform.position, FlightGlobals.currentMainBody), FlightGlobals.getExternalTemperature(), FlightGlobals.currentMainBody); - } - - void FixedUpdate() - { - if(!gameObject.activeInHierarchy) - { - return; - } - - //gravity - velocity += FlightGlobals.getGeeForceAtPosition(transform.position)*TimeWarp.fixedDeltaTime; - - //drag - velocity -= 0.005f * velocity * atmDensity; - - transform.rotation *= Quaternion.Euler(angularVelocity*TimeWarp.fixedDeltaTime); - transform.position += velocity*TimeWarp.deltaTime; - - if(BDArmorySettings.SHELL_COLLISIONS) - { - RaycastHit hit; - if(Physics.Linecast(transform.position, transform.position + velocity * Time.fixedDeltaTime, out hit, 557057)) - { - velocity = Vector3.Reflect(velocity, hit.normal); - velocity *= 0.55f; - velocity = Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 90f), UnityEngine.Random.onUnitSphere) * velocity; - } - } - } - - void Update() - { - if(!gameObject.activeInHierarchy) - { - return; - } - - if (Time.time - startTime > 2) - { - gameObject.SetActive(false); - } - } - } -} - diff --git a/BahaTurret/TGPCamRotator.cs b/BahaTurret/TGPCamRotator.cs deleted file mode 100644 index 3bcd40775..000000000 --- a/BahaTurret/TGPCamRotator.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; -namespace BahaTurret -{ - public class TGPCamRotator : MonoBehaviour - { - - void OnPreRender() - { - if(TargetingCamera.Instance) - { - TargetingCamera.Instance.UpdateCamRotation(transform); - } - } - } -} - diff --git a/BahaTurret/TGPCameraEffects.cs b/BahaTurret/TGPCameraEffects.cs deleted file mode 100644 index d9cba0411..000000000 --- a/BahaTurret/TGPCameraEffects.cs +++ /dev/null @@ -1,47 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class TGPCameraEffects : MonoBehaviour - { - public static Material grayscaleMaterial; - - public Texture textureRamp; - public float rampOffset; - - - void Awake() - { - if(!grayscaleMaterial) - { - grayscaleMaterial = new Material(BDAShaderLoader.GrayscaleEffectShader);//LoadManifestShader("BahaTurret.GrayscaleEffectShader.shader")); - grayscaleMaterial.SetTexture("_RampTex", textureRamp); - grayscaleMaterial.SetFloat("_RampOffset", rampOffset); - } - } - - - - void OnRenderImage (RenderTexture source, RenderTexture destination) - { - if(BDArmorySettings.BW_TARGET_CAM || TargetingCamera.Instance.nvMode) - { - Graphics.Blit (source, destination, grayscaleMaterial); //apply grayscale - } - } - - - } -} - diff --git a/BahaTurret/TargetInfo.cs b/BahaTurret/TargetInfo.cs deleted file mode 100644 index 8c0d6b4b3..000000000 --- a/BahaTurret/TargetInfo.cs +++ /dev/null @@ -1,284 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -namespace BahaTurret -{ - public class TargetInfo : MonoBehaviour - { - public BDArmorySettings.BDATeams team; - public bool isMissile = false; - - public MissileLauncher missileModule = null; - - public MissileFire weaponManager; - - - public bool isLanded - { - get - { - if(!vessel) return false; - - return vessel.LandedOrSplashed; - } - } - public Vector3 velocity - { - get - { - if(!vessel) return Vector3.zero; - return vessel.srf_velocity; - } - } - public Vector3 position - { - get - { - return vessel.vesselTransform.position; - } - } - - private Vessel vessel; - public Vessel Vessel - { - get - { - if(!vessel) - { - vessel = GetComponent(); - } - - return vessel; - } - set - { - vessel = value; - } - } - - public bool isThreat - { - get - { - if(!Vessel) - { - return false; - } - - if(isMissile && missileModule && !missileModule.hasMissed) - { - return true; - } - else if(weaponManager && weaponManager.vessel.IsControllable) - { - return true; - } - - return false; - } - } - - List friendliesEngaging; - - - void Awake() - { - if(!vessel) - { - vessel = GetComponent(); - } - if(!vessel) - { - Debug.Log ("TargetInfo was added to a non-vessel"); - Destroy (this); - return; - } - - //destroy this if a target info is already attached to the vessel - foreach(var otherInfo in vessel.gameObject.GetComponents()) - { - if(otherInfo != this) - { - Destroy(this); - return; - } - } - - team = BDArmorySettings.BDATeams.None; - - bool foundMf = false; - foreach(var mf in vessel.FindPartModulesImplementing()) - { - foundMf = true; - team = BDATargetManager.BoolToTeam(mf.team); - weaponManager = mf; - break; - } - if(!foundMf) - { - foreach(var ml in vessel.FindPartModulesImplementing()) - { - isMissile = true; - missileModule = ml; - team = BDATargetManager.BoolToTeam(ml.team); - break; - } - } - - if(team != BDArmorySettings.BDATeams.None) - { - if(!BDATargetManager.TargetDatabase[BDATargetManager.OtherTeam(team)].Contains(this)) - { - BDATargetManager.TargetDatabase[BDATargetManager.OtherTeam(team)].Add(this); - } - } - - friendliesEngaging = new List(); - - vessel.OnJustAboutToBeDestroyed += AboutToBeDestroyed; - lifeRoutine = StartCoroutine(LifetimeRoutine()); - //add delegate to peace enable event - BDArmorySettings.OnPeaceEnabled += OnPeaceEnabled; - - if(!isMissile && team != BDArmorySettings.BDATeams.None) - { - massRoutine = StartCoroutine(MassRoutine()); - } - } - - void OnPeaceEnabled() - { - if(lifeRoutine != null) - { - StopCoroutine(lifeRoutine); - } - if(massRoutine != null) - { - StopCoroutine(massRoutine); - } - - Destroy(this); - } - - void OnDestroy() - { - //remove delegate from peace enable event - BDArmorySettings.OnPeaceEnabled -= OnPeaceEnabled; - } - - public float detectedTime; - Coroutine lifeRoutine; - IEnumerator LifetimeRoutine() - { - detectedTime = Time.time; - while(Time.time - detectedTime < 60 && enabled) - { - yield return null; - } - if(massRoutine != null) - { - StopCoroutine(massRoutine); - } - Destroy(this); - } - - Coroutine massRoutine; - IEnumerator MassRoutine() - { - float startMass = vessel.GetTotalMass(); - while(enabled) - { - if(vessel.GetTotalMass() < startMass / 4) - { - if(lifeRoutine != null) - { - StopCoroutine(lifeRoutine); - } - - RemoveFromDatabases(); - yield break; - } - - yield return new WaitForSeconds(1); - } - } - - void Update() - { - if(!vessel) - { - AboutToBeDestroyed(); - } - else - { - if(vessel.vesselType == VesselType.Debris) - { - RemoveFromDatabases(); - team = BDArmorySettings.BDATeams.None; - } - } - } - - public int numFriendliesEngaging - { - get - { - if(friendliesEngaging == null) - { - return 0; - } - friendliesEngaging.RemoveAll(item => item == null); - return friendliesEngaging.Count; - } - } - - public void Engage(MissileFire mf) - { - /* - if(!hasStarted) - { - Start(); - } - */ - if(!friendliesEngaging.Contains(mf)) - { - friendliesEngaging.Add(mf); - } - } - - public void Disengage(MissileFire mf) - { - friendliesEngaging.Remove(mf); - } - - void AboutToBeDestroyed() - { - RemoveFromDatabases(); - Destroy(this); - } - - public bool IsCloser(TargetInfo otherTarget, MissileFire myMf) - { - float thisSqrDist = (position-myMf.transform.position).sqrMagnitude; - float otherSqrDist = (otherTarget.position-myMf.transform.position).sqrMagnitude; - return thisSqrDist < otherSqrDist; - } - - public void RemoveFromDatabases() - { - BDATargetManager.TargetDatabase[BDArmorySettings.BDATeams.A].Remove(this); - BDATargetManager.TargetDatabase[BDArmorySettings.BDATeams.B].Remove(this); - } - } -} - diff --git a/BahaTurret/TargetSignatureData.cs b/BahaTurret/TargetSignatureData.cs deleted file mode 100644 index a779be8f3..000000000 --- a/BahaTurret/TargetSignatureData.cs +++ /dev/null @@ -1,200 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; -namespace BahaTurret -{ - public struct TargetSignatureData : IEquatable - { - public Vector3 velocity; - public Vector3 geoPos; - public Vector3 acceleration; - public bool exists; - public float timeAcquired; - - public float signalStrength; - - public TargetInfo targetInfo; - - public BDArmorySettings.BDATeams team; - - public Vector2 pingPosition; - - public VesselECMJInfo vesselJammer; - - public ModuleRadar lockedByRadar; - - public Vessel vessel; - - bool orbital; - Orbit orbit; - - public bool Equals(TargetSignatureData other) - { - return - exists == other.exists && - geoPos == other.geoPos && - timeAcquired == other.timeAcquired; - } - - - public TargetSignatureData(Vessel v, float _signalStrength) - { - /* - if(v.situation == Vessel.Situations.SUB_ORBITAL || v.situation == Vessel.Situations.ESCAPING || v.situation == Vessel.Situations.SUB_ORBITAL) - { - velocity = v.obt_velocity; - orbit = v.orbit; - orbital = true; - } - else - { - */ - orbital = false; - orbit = null; - velocity = v.srf_velocity; - //} - vessel = v; - geoPos = VectorUtils.WorldPositionToGeoCoords(v.CoM, v.mainBody); - acceleration = v.acceleration; - exists = true; - timeAcquired = Time.time; - signalStrength = _signalStrength; - - targetInfo = v.gameObject.GetComponent (); - - team = BDArmorySettings.BDATeams.None; - if(targetInfo) - { - team = targetInfo.team; - } - else - { - foreach(var mf in v.FindPartModulesImplementing()) - { - team = BDATargetManager.BoolToTeam(mf.team); - break; - } - } - - vesselJammer = v.gameObject.GetComponent(); - - pingPosition = Vector2.zero; - - lockedByRadar = null; - } - - public TargetSignatureData(CMFlare flare, float _signalStrength) - { - velocity = flare.velocity; - geoPos = VectorUtils.WorldPositionToGeoCoords(flare.transform.position, FlightGlobals.currentMainBody); - exists = true; - acceleration = Vector3.zero; - timeAcquired = Time.time; - signalStrength = _signalStrength; - targetInfo = null; - vesselJammer = null; - team = BDArmorySettings.BDATeams.None; - pingPosition = Vector2.zero; - orbital = false; - orbit = null; - lockedByRadar = null; - vessel = null; - } - - public TargetSignatureData(Vector3 _velocity, Vector3 _position, Vector3 _acceleration, bool _exists, float _signalStrength) - { - velocity = _velocity; - geoPos = VectorUtils.WorldPositionToGeoCoords(_position, FlightGlobals.currentMainBody); - acceleration = _acceleration; - exists = _exists; - timeAcquired = Time.time; - signalStrength = _signalStrength; - targetInfo = null; - vesselJammer = null; - team = BDArmorySettings.BDATeams.None; - pingPosition = Vector2.zero; - orbital = false; - orbit = null; - lockedByRadar = null; - vessel = null; - } - - public Vector3 position - { - get - { - if(orbital) - { - return orbit.pos.xzy; - } - else - { - //return FlightGlobals.currentMainBody.GetWorldSurfacePosition(geoPos.x, geoPos.y, geoPos.z); - return VectorUtils.GetWorldSurfacePostion(geoPos, FlightGlobals.currentMainBody); - } - } - set - { - geoPos = VectorUtils.WorldPositionToGeoCoords(value, FlightGlobals.currentMainBody); - } - } - - public Vector3 predictedPosition - { - get - { - if(orbital) - { - return orbit.getPositionAtUT(Planetarium.GetUniversalTime()).xzy; - } - else - { - return position + (velocity * age) + (0.5f * acceleration * age * age); - } - } - } - - public float altitude - { - get - { - return geoPos.z; - } - } - - public float age - { - get - { - return Time.time-timeAcquired; - } - } - - public static TargetSignatureData noTarget - { - get - { - return new TargetSignatureData(Vector3.zero, Vector3.zero, Vector3.zero, false, 0); - } - } - - public static void ResetTSDArray(ref TargetSignatureData[] tsdArray) - { - for(int i = 0; i < tsdArray.Length; i++) - { - tsdArray[i] = TargetSignatureData.noTarget; - } - } - - - } -} - diff --git a/BahaTurret/TargetingCamera.cs b/BahaTurret/TargetingCamera.cs deleted file mode 100644 index 3bd29b9b1..000000000 --- a/BahaTurret/TargetingCamera.cs +++ /dev/null @@ -1,395 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public class TargetingCamera : MonoBehaviour - { - public static TargetingCamera Instance; - public static bool ReadyForUse = false; - public RenderTexture targetCamRenderTexture; - TGPCameraEffects camEffects; - Light nvLight; - public bool nvMode = false; - - - private Texture2D reticleTex; - public Texture2D ReticleTexture - { - get - { - if(reticleTex!=null) - { - return reticleTex; - } - else - { - reticleTex = GameDatabase.Instance.GetTexture("BDArmory/Textures/camReticle",false); - return reticleTex; - } - } - } - - - Camera[] cameras; - public static Transform cameraTransform; - - bool cameraEnabled = false; - - float currentFOV = 60; - - void Awake() - { - if(Instance) - { - Destroy (gameObject); - return; - } - else - { - Instance = this; - } - } - - void Start() - { - GameEvents.onVesselChange.Add(VesselChange); - } - - /* - void LateUpdate() - { - if(cameraEnabled) - { - if(cameras!=null && cameras[0]!=null) - { - Quaternion cRotation = cameras[0].transform.rotation; - cameras[2].transform.rotation = cRotation; - cameras[3].transform.rotation = cRotation; - } - else - { - cameraEnabled = false; - } - } - } - */ - - public void UpdateCamRotation(Transform tf) - { - if(cameras!=null && cameras[0]!=null) - { - tf.rotation = cameras[0].transform.rotation; - } - } - - public void SetFOV(float fov) - { - if(fov == currentFOV) - { - return; - } - - if(cameras == null || cameras[0] == null) - { - if(cameraEnabled) - { - DisableCamera(); - } - return; - } - - for(int i = 0; i < cameras.Length; i++) - { - cameras[i].fieldOfView = fov; - } - currentFOV = fov; - } - - void VesselChange(Vessel v) - { - if(!v.isActiveVessel) - { - return; - } - - /* - if(!FlightGlobals.ready) - { - return; - } - - if(!FlightCamera.fetch) - { - return; - } - - if(!FlightCamera.fetch.mainCamera) - { - return; - } - */ - bool moduleFound = false; - foreach(var mtc in v.FindPartModulesImplementing()) - { - Debug.Log ("Vessel switched to vessel with targeting camera. Refreshing camera state."); - - if(mtc.cameraEnabled) - { - mtc.DelayedEnable(); - } - else - { - mtc.DisableCamera(); - } - moduleFound = true; - } - - if(!moduleFound) - { - DisableCamera(); - ModuleTargetingCamera.windowIsOpen = false; - } - } - - public void EnableCamera(Transform parentTransform) - { - if(cameraTransform) - { - cameraTransform.gameObject.SetActive(true); - } - - SetupCamera(parentTransform); - - for(int i = 0; i < cameras.Length; i++) - { - cameras[i].enabled = false; - } - - cameraEnabled = true; - - ReadyForUse = true; - - } - - void RenderCameras() - { - cameras[3].Render(); - cameras[2].Render(); - - /* - if(ModuleWeapon.bulletPool) - { - for(int i = 0; i < ModuleWeapon.bulletPool.size; i++) - { - if(ModuleWeapon.bulletPool.GetPooledObject(i).activeInHierarchy) - { - PooledBullet pBullet = ModuleWeapon.bulletPool.GetPooledObject(i).GetComponent(); - pBullet.UpdateWidth(cameras[1], 3); - } - - } - } - */ - Color origAmbientColor = RenderSettings.ambientLight; - if(nvMode) - { - RenderSettings.ambientLight = new Color(0.5f,0.5f,0.5f,1); - nvLight.enabled = true; - } - cameras[1].Render(); - cameras[0].Render(); - - nvLight.enabled = false; - if(nvMode) - { - RenderSettings.ambientLight = origAmbientColor; - } - - - } - - void LateUpdate() - { - if(cameraEnabled) - { - if(cameras == null || cameras[0] == null) - { - DisableCamera(); - return; - } - RenderCameras(); - } - } - - public void DisableCamera() - { - - if(cameraTransform) - { - cameraTransform.parent = null; - cameraTransform.gameObject.SetActive(false); - } - - if(cameras!=null && cameras[0]!=null) - { - for(int i = 0; i < cameras.Length; i++) - { - cameras[i].enabled = false; - } - } - - cameraEnabled = false; - } - - void SetupCamera(Transform parentTransform) - { - if(!parentTransform) - { - Debug.Log ("Targeting camera tried setup but parent transform is null"); - return; - } - - if(cameraTransform == null) - { - cameraTransform = (new GameObject("targetCamObject")).transform; - } - - Debug.Log ("Setting target camera parent"); - cameraTransform.parent = parentTransform; - cameraTransform.localPosition = Vector3.zero; - cameraTransform.localRotation = Quaternion.identity; - - if(targetCamRenderTexture == null) - { - int res = Mathf.RoundToInt(BDArmorySettings.TARGET_CAM_RESOLUTION); - targetCamRenderTexture = new RenderTexture(res,res,24); - targetCamRenderTexture.antiAliasing = 1; - targetCamRenderTexture.Create(); - - } - - - if(cameras != null && cameras[0] != null) - { - return; - } - - //cam setup - cameras = new Camera[4]; - - - Camera fCamNear = FlightCamera.fetch.cameras[0]; - Camera fCamFar = FlightCamera.fetch.cameras[1]; - - - //flight cameras - //nearCam - GameObject cam1Obj = new GameObject(); - Camera nearCam = cam1Obj.AddComponent(); - nearCam.CopyFrom(fCamNear); - nearCam.transform.parent = cameraTransform; - nearCam.transform.localRotation = Quaternion.identity; - nearCam.transform.localPosition = Vector3.zero; - nearCam.transform.localScale = Vector3.one; - nearCam.targetTexture = targetCamRenderTexture; - cameras[0] = nearCam; - - - TGPCameraEffects ge1 = cam1Obj.AddComponent(); - ge1.textureRamp = GameDatabase.Instance.GetTexture("BDArmory/Textures/grayscaleRamp", false); - ge1.rampOffset = 0; - camEffects = ge1; - - //farCam - GameObject cam2Obj = new GameObject(); - Camera farCam = cam2Obj.AddComponent(); - farCam.CopyFrom(fCamFar); - farCam.transform.parent = cameraTransform; - farCam.transform.localRotation = Quaternion.identity; - farCam.transform.localPosition = Vector3.zero; - farCam.transform.localScale = Vector3.one; - farCam.targetTexture = targetCamRenderTexture; - cameras[1] = farCam; - - /* - var cbr2 = cam2Obj.AddComponent(); - cbr2.resizeFactor = 3f; - */ - - //skybox camera - GameObject skyCamObj = new GameObject(); - Camera skyCam = skyCamObj.AddComponent(); - Camera mainSkyCam = FindCamera("Camera ScaledSpace"); - skyCam.CopyFrom(mainSkyCam); - skyCam.transform.parent = mainSkyCam.transform; - skyCam.transform.localRotation = Quaternion.identity; - skyCam.transform.localPosition = Vector3.zero; - skyCam.transform.localScale = Vector3.one; - skyCam.targetTexture = targetCamRenderTexture; - cameras[cameras.Length-2] = skyCam; - skyCamObj.AddComponent(); - - //galaxy camera - GameObject galaxyCamObj = new GameObject(); - Camera galaxyCam = galaxyCamObj.AddComponent(); - Camera mainGalaxyCam = FindCamera("GalaxyCamera"); - galaxyCam.CopyFrom(mainGalaxyCam); - galaxyCam.transform.parent = mainGalaxyCam.transform; - galaxyCam.transform.position = Vector3.zero; - galaxyCam.transform.localRotation = Quaternion.identity; - galaxyCam.transform.localScale = Vector3.one; - galaxyCam.targetTexture = targetCamRenderTexture; - cameras[cameras.Length-1] = galaxyCam; - galaxyCamObj.AddComponent(); - - nvLight = new GameObject().AddComponent(); - nvLight.transform.parent = cameraTransform; - nvLight.transform.localPosition = Vector3.zero; - nvLight.transform.localRotation = Quaternion.identity; - nvLight.type = LightType.Directional; - nvLight.intensity = 2; - nvLight.shadows = LightShadows.None; - - nvLight.cullingMask = 1 << 0; - nvLight.enabled = false; - } - - - - private Camera FindCamera(string cameraName) - { - foreach(var cam in Camera.allCameras) - { - if(cam.name == cameraName) - { - return cam; - } - } - Debug.Log ("Couldn't find "+cameraName); - return null; - } - - - - void OnDestroy() - { - ReadyForUse = false; - } - - public static bool IsTGPCamera(Camera c) - { - return c.transform == cameraTransform; - } - } -} - diff --git a/BahaTurret/UnlitBlack.shader b/BahaTurret/UnlitBlack.shader deleted file mode 100644 index 8bd2d5b35..000000000 --- a/BahaTurret/UnlitBlack.shader +++ /dev/null @@ -1,12 +0,0 @@ -Shader "Custom/Unlit Black" { - -Properties { - //_Color ("Color", Color) = (1,1,1) -} - -SubShader { - Color (0,0,0)//[_Color] - Pass {} -} - -} diff --git a/BahaTurret/VectorUtils.cs b/BahaTurret/VectorUtils.cs deleted file mode 100644 index 432083cf0..000000000 --- a/BahaTurret/VectorUtils.cs +++ /dev/null @@ -1,153 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18449 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public static class VectorUtils - { - public static float SignedAngle(Vector3 fromDirection, Vector3 toDirection, Vector3 referenceRight) - { - float angle = Vector3.Angle(fromDirection, toDirection); - float sign = Mathf.Sign(Vector3.Dot(toDirection, referenceRight)); - float finalAngle = sign * angle; - return finalAngle; - } - - - - //from howlingmoonsoftware.com - //calculates how long it will take for a target to be where it will be when a bullet fired now can reach it. - //delta = initial relative position, vr = relative velocity, muzzleV = bullet velocity. - public static float CalculateLeadTime(Vector3 delta, Vector3 vr, float muzzleV) - { - // Quadratic equation coefficients a*t^2 + b*t + c = 0 - float a = Vector3.Dot(vr, vr) - muzzleV*muzzleV; - float b = 2f*Vector3.Dot(vr, delta); - float c = Vector3.Dot(delta, delta); - - float det = b*b - 4f*a*c; - - // If the determinant is negative, then there is no solution - if(det > 0f) - { - return 2f*c/(Mathf.Sqrt(det) - b); - } - else - { - return -1f; - } - } - - /// - /// Returns a value between -1 and 1 via Perlin noise. - /// - /// Returns a value between -1 and 1 via Perlin noise. - /// The x coordinate. - /// The y coordinate. - public static float FullRangePerlinNoise(float x, float y) - { - float perlin = Mathf.PerlinNoise(x,y); - - perlin -= 0.5f; - perlin *= 2; - - return perlin; - } - - - public static Vector3 RandomDirectionDeviation(Vector3 direction, float maxAngle) - { - return Vector3.RotateTowards(direction, UnityEngine.Random.rotation*direction, UnityEngine.Random.Range(0, maxAngle*Mathf.Deg2Rad), 0).normalized; - } - - public static Vector3 WeightedDirectionDeviation(Vector3 direction, float maxAngle) - { - float random = UnityEngine.Random.Range(0f, 1f); - float maxRotate = maxAngle*(random * random); - maxRotate = Mathf.Clamp(maxRotate, 0, maxAngle)*Mathf.Deg2Rad; - return Vector3.RotateTowards(direction, Vector3.ProjectOnPlane(UnityEngine.Random.onUnitSphere, direction), maxRotate, 0).normalized; - } - - /// - /// Converts world position to Lat,Long,Alt form. - /// - /// The position in geo coords. - /// World position. - /// Body. - public static Vector3d WorldPositionToGeoCoords(Vector3d worldPosition, CelestialBody body) - { - if(!body) - { - //Debug.Log ("BahaTurret.VectorUtils.WorldPositionToGeoCoords body is null"); - return Vector3d.zero; - } - - double lat = body.GetLatitude(worldPosition); - double longi = body.GetLongitude(worldPosition); - double alt = body.GetAltitude(worldPosition); - return new Vector3d(lat,longi,alt); - } - - public static Vector3 RotatePointAround(Vector3 pointToRotate, Vector3 pivotPoint, Vector3 axis, float angle) - { - Vector3 line = pointToRotate-pivotPoint; - line = Quaternion.AngleAxis(angle, axis) * line; - return pivotPoint + line; - } - - public static Vector3 GetNorthVector(Vector3 position, CelestialBody body) - { - Vector3 geoPosA = VectorUtils.WorldPositionToGeoCoords(position, body); - Vector3 geoPosB = new Vector3(geoPosA.x+1, geoPosA.y, geoPosA.z); - Vector3 north = GetWorldSurfacePostion(geoPosB, body)-GetWorldSurfacePostion(geoPosA, body); - return Vector3.ProjectOnPlane(north, body.GetSurfaceNVector(geoPosA.x, geoPosA.y)).normalized; - } - - public static Vector3 GetWorldSurfacePostion(Vector3d geoPosition, CelestialBody body) - { - if(!body) - { - return Vector3.zero; - } - return body.GetWorldSurfacePosition(geoPosition.x, geoPosition.y, geoPosition.z); - } - - public static Vector3 GetUpDirection(Vector3 position) - { - return (position-FlightGlobals.currentMainBody.transform.position).normalized; - } - - public static bool SphereRayIntersect(Ray ray, Vector3 sphereCenter, double sphereRadius, out double distance) - { - Vector3 o = ray.origin; - Vector3 l = ray.direction; - Vector3d c = sphereCenter; - double r = sphereRadius; - - double d; - - d = -(Vector3.Dot(l, o - c) + Math.Sqrt(Mathf.Pow(Vector3.Dot(l, o - c), 2) - (o - c).sqrMagnitude + (r * r))); - - if(double.IsNaN(d)) - { - distance = 0; - return false; - } - else - { - distance = d; - return true; - } - } - } -} - diff --git a/BahaTurret/VesselChaffInfo.cs b/BahaTurret/VesselChaffInfo.cs deleted file mode 100644 index ea59c2065..000000000 --- a/BahaTurret/VesselChaffInfo.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - [RequireComponent(typeof(Vessel))] - public class VesselChaffInfo : MonoBehaviour - { - Vessel vessel; - - const float chaffMax = 500; - const float chaffSubtractor = 120; - const float speedRegenMult = 0.6f; - const float minRegen = 40; - const float maxRegen = 500; - const float minMult = 0.03f; - float chaffScalar = 500; - - void Awake() - { - vessel = GetComponent(); - if(!vessel) - { - Debug.Log("VesselChaffInfo was added to an object with no vessel component"); - Destroy(this); - return; - } - } - - public float GetChaffMultiplier() - { - return Mathf.Clamp(chaffScalar/chaffMax, minMult, 1f); - } - - public void Chaff() - { - chaffScalar = Mathf.Clamp(chaffScalar - chaffSubtractor, 0, chaffMax); - } - - void FixedUpdate() - { - chaffScalar = Mathf.MoveTowards(chaffScalar, chaffMax, Mathf.Clamp(speedRegenMult*(float)vessel.srfSpeed, minRegen, maxRegen) * Time.fixedDeltaTime); - } - - void OnGUI() - { - if(BDArmorySettings.DRAW_DEBUG_LABELS && vessel.isActiveVessel) - { - GUI.Label(new Rect(600, 600, 200, 200), "Chaff multiplier: " + GetChaffMultiplier()); - } - } - } -} - diff --git a/BahaTurret/VesselECMJInfo.cs b/BahaTurret/VesselECMJInfo.cs deleted file mode 100644 index 329c041db..000000000 --- a/BahaTurret/VesselECMJInfo.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -namespace BahaTurret -{ - [RequireComponent(typeof(Vessel))] - public class VesselECMJInfo : MonoBehaviour - { - List jammers; - public Vessel vessel; - - bool jEnabled; - public bool jammerEnabled - { - get - { - return jEnabled; - } - } - - float jStrength; - public float jammerStrength - { - get - { - return jStrength; - } - } - - float lbs; - public float lockBreakStrength - { - get - { - return lbs; - } - } - - float rcsr; - public float rcsReductionFactor - { - get - { - return rcsr; - } - } - - - - - void Awake() - { - jammers = new List(); - vessel = GetComponent(); - - GameEvents.onVesselCreate.Add(OnVesselCreate); - GameEvents.onPartJointBreak.Add(OnPartJointBreak); - GameEvents.onPartDie.Add(OnPartDie); - } - - void OnDestroy() - { - GameEvents.onVesselCreate.Remove(OnVesselCreate); - GameEvents.onPartJointBreak.Remove(OnPartJointBreak); - GameEvents.onPartDie.Remove(OnPartDie); - } - - void OnPartDie(Part p) - { - if(gameObject.activeInHierarchy) - { - StartCoroutine(DelayedCleanJammerListRoutine()); - } - } - - void OnVesselCreate(Vessel v) - { - if(gameObject.activeInHierarchy) - { - StartCoroutine(DelayedCleanJammerListRoutine()); - } - } - - void OnPartJointBreak(PartJoint j) - { - if(gameObject.activeInHierarchy) - { - StartCoroutine(DelayedCleanJammerListRoutine()); - } - } - - public void AddJammer(ModuleECMJammer jammer) - { - if(!jammers.Contains(jammer)) - { - jammers.Add(jammer); - } - - UpdateJammerStrength(); - } - - public void RemoveJammer(ModuleECMJammer jammer) - { - jammers.Remove(jammer); - - UpdateJammerStrength(); - } - - void UpdateJammerStrength() - { - jEnabled = jammers.Count > 0; - - if(!jammerEnabled) - { - jStrength = 0; - } - - float totaljStrength = 0; - float totalLBstrength = 0; - float jSpamFactor = 1; - float lbreakFactor = 1; - - float rcsrTotalMass = 0; - float rcsrTotal = 0; - float rcsrCount = 0; - - foreach(var jammer in jammers) - { - if(jammer.signalSpam) - { - totaljStrength += jSpamFactor * jammer.jammerStrength; - jSpamFactor *= 0.75f; - } - if(jammer.lockBreaker) - { - totalLBstrength += lbreakFactor * jammer.lockBreakerStrength; - lbreakFactor *= 0.65f; - } - if(jammer.rcsReduction) - { - rcsrTotalMass += jammer.part.mass; - rcsrTotal += jammer.rcsReductionFactor; - rcsrCount++; - } - } - - lbs = totalLBstrength; - jStrength = totaljStrength; - - if(rcsrCount > 0) - { - float rcsrAve = rcsrTotal / rcsrCount; - float massFraction = rcsrTotalMass / vessel.GetTotalMass(); - rcsr = Mathf.Clamp(1-(rcsrAve * massFraction), 0.15f, 1); - } - else - { - rcsr = 1; - } - } - - public void DelayedCleanJammerList() - { - StartCoroutine(DelayedCleanJammerListRoutine()); - } - - IEnumerator DelayedCleanJammerListRoutine() - { - yield return null; - yield return null; - CleanJammerList(); - } - - void CleanJammerList() - { - vessel = GetComponent(); - - if(!vessel) - { - Destroy(this); - } - jammers.RemoveAll(j => j == null); - jammers.RemoveAll(j => j.vessel != vessel); - - foreach(var jam in vessel.FindPartModulesImplementing()) - { - if(jam.jammerEnabled) - { - AddJammer(jam); - } - } - - - UpdateJammerStrength(); - } - - void OnGUI() - { - if(BDArmorySettings.DRAW_DEBUG_LABELS && vessel.isActiveVessel) - { - GUI.Label(new Rect(400, 500, 200, 200), "Total jammer strength: " + jammerStrength); - } - } - } -} - diff --git a/BahaTurret/VesselRadarData.cs b/BahaTurret/VesselRadarData.cs deleted file mode 100644 index f1a6b9a04..000000000 --- a/BahaTurret/VesselRadarData.cs +++ /dev/null @@ -1,1838 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class VesselRadarData : MonoBehaviour - { - private List availableRadars; - private List externalRadars; - private List externalVRDs; - - private int rCount = 0; - public int radarCount - { - get - { - return rCount; - } - } - - public bool guiEnabled - { - get - { - return drawGUI; - } - } - private bool drawGUI = false; - - public MissileFire weaponManager; - public bool canReceiveRadarData; - - //GUI - public static Rect radarWindowRect; - public bool linkWindowOpen = false; - float numberOfAvailableLinks = 0; - public Rect linkWindowRect = new Rect(0,0,0,0); - float linkRectWidth = 200; - float linkRectEntryHeight = 26; - - public static bool radarRectInitialized = false; - float radarScreenSize = 360; - Rect radarRect; - float windowBorder = 10; - float headerHeight = 12; - float controlsHeight = 58; - Vector2 pingSize = new Vector2(16,8); - Texture2D rollIndicatorTexture = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "radarRollIndicator", false); - public static Texture2D omniBgTexture = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "omniRadarTexture", false); - Texture2D radialBgTexture = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "radialRadarTexture", false); - Texture2D scanTexture = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "omniRadarScanTexture", false); - Texture2D lockIcon = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "lockedRadarIcon", false); - Texture2D lockIconActive = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "lockedRadarIconActive", false); - Texture2D radarContactIcon = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "radarContactIcon", false); - Texture2D friendlyContactIcon = GameDatabase.Instance.GetTexture(BDArmorySettings.textureDir + "friendlyContactIcon", false); - float lockIconSize = 24; - GUIStyle distanceStyle; - GUIStyle lockStyle; - GUIStyle radarTopStyle; - - bool noData = false; - - float guiInputTime = 0; - float guiInputCooldown = 0.2f; - - //range increments - public float[] rIncrements = new float[]{5000,10000,20000}; - int rangeIndex = 0; - - //lock cursor - bool showSelector = false; - Vector2 selectorPos = Vector2.zero; - - //data link - private List availableExternalVRDs; - - private Transform referenceTransform; - private Transform vesselReferenceTransform; - - public MissileLauncher lastMissile; - - //bool boresightScan = false; - - //TargetSignatureData[] contacts = new TargetSignatureData[30]; - List displayedTargets; - public bool locked = false; - int activeLockedTargetIndex = 0; - List lockedTargetIndexes; - - public bool hasLoadedExternalVRDs = false; - - public List GetLockedTargets() - { - List lockedTargets = new List(); - for(int i = 0; i < lockedTargetIndexes.Count; i++) - { - lockedTargets.Add(displayedTargets[lockedTargetIndexes[i]].targetData); - } - return lockedTargets; - } - - public RadarDisplayData lockedTargetData - { - get - { - return displayedTargets[lockedTargetIndexes[activeLockedTargetIndex]]; - } - } - - //turret slaving - public bool slaveTurrets = false; - - Vessel myVessel; - public Vessel vessel - { - get - { - return myVessel; - } - } - - public void AddRadar(ModuleRadar mr) - { - if(availableRadars.Contains(mr)) - { - return; - } - - availableRadars.Add(mr); - rCount = availableRadars.Count; - //UpdateDataLinkCapability(); - linkCapabilityDirty = true; - } - - public void RemoveRadar(ModuleRadar mr) - { - availableRadars.Remove(mr); - rCount = availableRadars.Count; - RemoveDataFromRadar(mr); - //UpdateDataLinkCapability(); - linkCapabilityDirty = true; - } - - public bool linkCapabilityDirty = false; - public bool radarsReady = false; - - void Awake() - { - availableRadars = new List(); - externalRadars = new List(); - myVessel = GetComponent(); - lockedTargetIndexes = new List(); - availableExternalVRDs = new List(); - - distanceStyle = new GUIStyle(); - distanceStyle.normal.textColor = new Color(0,1,0,0.75f); - distanceStyle.alignment = TextAnchor.UpperLeft; - - lockStyle = new GUIStyle(); - lockStyle.normal.textColor = new Color(0,1,0,0.75f); - lockStyle.alignment = TextAnchor.LowerCenter; - lockStyle.fontSize = 16; - - radarTopStyle = new GUIStyle(); - radarTopStyle.normal.textColor = new Color(0, 1, 0, 0.65f); - radarTopStyle.alignment = TextAnchor.UpperCenter; - radarTopStyle.fontSize = 12; - - vesselReferenceTransform = (new GameObject()).transform; - //vesselReferenceTransform.parent = vessel.transform; - //vesselReferenceTransform.localPosition = Vector3.zero; - vesselReferenceTransform.localScale = Vector3.one; - - displayedTargets = new List(); - externalVRDs = new List(); - waitingForVessels = new List(); - - radarRect = new Rect(0,0,radarScreenSize,radarScreenSize); - - if(!radarRectInitialized) - { - float width = radarScreenSize + (2*windowBorder); - float height = radarScreenSize + (2*windowBorder) + headerHeight + controlsHeight; - radarWindowRect = new Rect(Screen.width - width, Screen.height - height, width, height); - radarRectInitialized = true; - } - } - - void Start() - { - rangeIndex = rIncrements.Length - 1; - UpdateLockedTargets(); - - foreach(var mf in vessel.FindPartModulesImplementing()) - { - mf.vesselRadarData = this; - } - - GameEvents.onVesselDestroy.Add(OnVesselDestroyed); - GameEvents.onVesselCreate.Add(OnVesselDestroyed); - MissileFire.OnToggleTeam += OnToggleTeam; - GameEvents.onGameStateSave.Add(OnGameStateSave); - GameEvents.onPartDestroyed.Add(PartDestroyed); - - if(!weaponManager) - { - foreach(var mf in vessel.FindPartModulesImplementing()) - { - weaponManager = mf; - break; - } - } - - StartCoroutine(StartupRoutine()); - } - - IEnumerator StartupRoutine() - { - while(!FlightGlobals.ready || vessel.packed) - { - yield return null; - } - - yield return new WaitForFixedUpdate(); - yield return new WaitForFixedUpdate(); - radarsReady = true; - } - - void OnGameStateSave(ConfigNode n) - { - SaveExternalVRDVessels(); - } - - void SaveExternalVRDVessels() - { - string linkedVesselID = ""; - - foreach(var v in externalVRDs) - { - linkedVesselID += v.vessel.id.ToString() + ","; - } - - foreach(var id in waitingForVessels) - { - linkedVesselID += id + ","; - } - - foreach(var radar in availableRadars) - { - if(radar.vessel == vessel) - { - radar.linkedVesselID = linkedVesselID; - return; - } - } - } - - void OnDestroy() - { - GameEvents.onVesselDestroy.Remove(OnVesselDestroyed); - GameEvents.onVesselCreate.Remove(OnVesselDestroyed); - MissileFire.OnToggleTeam -= OnToggleTeam; - - if(weaponManager) - { - if(slaveTurrets) - { - weaponManager.slavingTurrets = false; - } - } - } - - void OnToggleTeam(MissileFire wm, BDArmorySettings.BDATeams team) - { - if(!weaponManager || !wm) return; - - if(team != BDATargetManager.BoolToTeam(weaponManager.team)) - { - if(wm.vesselRadarData) - { - UnlinkVRD(wm.vesselRadarData); - } - } - else if(wm.vessel == vessel) - { - UnlinkAllExternalRadars(); - } - - RemoveDisconnectedRadars(); - } - - void UpdateDataLinkCapability() - { - canReceiveRadarData = false; - noData = true; - foreach(var mr in availableRadars) - { - if(mr.vessel == vessel && mr.canRecieveRadarData) - { - canReceiveRadarData = true; - } - - if(mr.canScan) - { - noData = false; - } - } - - if(!canReceiveRadarData) - { - UnlinkAllExternalRadars(); - } - - foreach(var mr in availableRadars) - { - if(mr.canScan) - { - noData = false; - } - } - } - - void UpdateReferenceTransform() - { - if(radarCount == 1 && !availableRadars[0].omnidirectional && !vessel.Landed) - { - referenceTransform = availableRadars[0].referenceTransform; - } - else - { - referenceTransform = vesselReferenceTransform; - } - } - - void PartDestroyed(Part p) - { - RemoveDisconnectedRadars(); - UpdateLockedTargets(); - RefreshAvailableLinks(); - } - - void OnVesselDestroyed(Vessel v) - { - RemoveDisconnectedRadars(); - UpdateLockedTargets(); - RefreshAvailableLinks(); - } - - void RemoveDisconnectedRadars() - { - availableRadars.RemoveAll(r => r == null); - List radarsToRemove = new List(); - foreach(var radar in availableRadars) - { - if(!radar.radarEnabled || (radar.vessel != vessel && !externalRadars.Contains(radar))) - { - radarsToRemove.Add(radar); - } - else if(!radar.weaponManager || (weaponManager && radar.weaponManager.team != weaponManager.team)) - { - radarsToRemove.Add(radar); - } - } - - foreach(var radar in radarsToRemove) - { - RemoveRadar(radar); - } - rCount = availableRadars.Count; - - RemoveEmptyVRDs(); - } - - public void UpdateLockedTargets() - { - locked = false; - - lockedTargetIndexes.Clear();// = new List(); - - for(int i = 0; i < displayedTargets.Count; i++) - { - if(displayedTargets[i].vessel && displayedTargets[i].locked) - { - locked = true; - lockedTargetIndexes.Add(i); - } - } - - if(locked) - { - activeLockedTargetIndex = Mathf.Clamp(activeLockedTargetIndex, 0, lockedTargetIndexes.Count - 1); - } - else - { - activeLockedTargetIndex = 0; - } - } - - void UpdateSlaveData() - { - if(slaveTurrets && weaponManager) - { - weaponManager.slavingTurrets = true; - if(locked) - { - TargetSignatureData lockedTarget = lockedTargetData.targetData; - weaponManager.slavedPosition = lockedTarget.predictedPosition; - weaponManager.slavedVelocity = lockedTarget.velocity; - weaponManager.slavedAcceleration = lockedTarget.acceleration; - } - } - } - - void Update() - { - - - if(!vessel) - { - Destroy(this); - return; - } - - UpdateReferenceTransform(); - - if(radarCount > 0) - { - //vesselReferenceTransform.parent = linkedRadars[0].transform; - vesselReferenceTransform.localScale = Vector3.one; - vesselReferenceTransform.position = vessel.CoM; - - if(vessel.Landed) - { - vesselReferenceTransform.rotation = Quaternion.LookRotation(VectorUtils.GetNorthVector(vessel.transform.position, vessel.mainBody), vessel.upAxis); - } - else - { - vesselReferenceTransform.rotation = Quaternion.LookRotation(Vector3.ProjectOnPlane(vessel.transform.up, vessel.upAxis), vessel.upAxis); - } - - CleanDisplayedContacts(); - - UpdateInputs(); - - UpdateSlaveData(); - } - else - { - if(slaveTurrets) - { - UnslaveTurrets(); - } - } - - - - if(linkCapabilityDirty) - { - UpdateDataLinkCapability(); - - linkCapabilityDirty = false; - } - - drawGUI = (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && !vessel.packed && rCount > 0 && vessel.isActiveVessel && BDArmorySettings.GAME_UI_ENABLED && !MapView.MapIsEnabled); - - if(!vessel.loaded && radarCount == 0) - { - Destroy(this); - } - } - - public bool autoCycleLockOnFire = true; - public void CycleActiveLock() - { - if(locked) - { - activeLockedTargetIndex++; - if(activeLockedTargetIndex >= lockedTargetIndexes.Count) - { - activeLockedTargetIndex = 0; - } - - lockedTargetData.detectedByRadar.SetActiveLock(lockedTargetData.targetData); - - UpdateLockedTargets(); - } - } - - - void IncreaseRange() - { - int origIndex = rangeIndex; - rangeIndex = Mathf.Clamp(rangeIndex+1, 0, rIncrements.Length-1); - if(origIndex != rangeIndex) - { - pingPositionsDirty = true; - } - } - - void DecreaseRange() - { - int origIndex = rangeIndex; - rangeIndex = Mathf.Clamp(rangeIndex-1, 0, rIncrements.Length-1); - if(origIndex != rangeIndex) - { - pingPositionsDirty = true; - } - } - - bool TryLockTarget(RadarDisplayData radarTarget) - { - if(radarTarget.locked) return false; - - ModuleRadar lockingRadar = null; - //first try using the last radar to detect that target - if(CheckRadarForLock(radarTarget.detectedByRadar, radarTarget)) - { - lockingRadar = radarTarget.detectedByRadar; - } - else - { - foreach(var radar in availableRadars) - { - if(CheckRadarForLock(radar, radarTarget)) - { - lockingRadar = radar; - break; - } - } - } - - if(lockingRadar != null) - { - return lockingRadar.TryLockTarget(radarTarget.targetData.predictedPosition); - } - - UpdateLockedTargets(); - StartCoroutine(UpdateLocksAfterFrame()); - return false; - } - - IEnumerator UpdateLocksAfterFrame() - { - yield return null; - UpdateLockedTargets(); - } - - public void TryLockTarget(Vector3 worldPosition) - { - foreach(var displayData in displayedTargets) - { - if(Vector3.SqrMagnitude(worldPosition - displayData.targetData.predictedPosition) < 40 * 40) - { - TryLockTarget(displayData); - return; - } - } - return; - } - - public bool TryLockTarget(Vessel v) - { - if(!v) return false; - - foreach(var displayData in displayedTargets) - { - if(v == displayData.vessel) - { - return TryLockTarget(displayData); - } - } - - RadarDisplayData newData = new RadarDisplayData(); - newData.vessel = v; - newData.detectedByRadar = null; - newData.targetData = new TargetSignatureData(v, 999); - - return TryLockTarget(newData); - - //return false; - } - - bool CheckRadarForLock(ModuleRadar radar, RadarDisplayData radarTarget) - { - if(!radar) return false; - - return - ( - radar.canLock - && (!radar.locked || radar.currentLocks < radar.maxLocks) - && radarTarget.targetData.signalStrength > radar.minLockedSignalThreshold - && (radar.omnidirectional || Vector3.Angle(radar.transform.up, radarTarget.targetData.predictedPosition-radar.transform.position) < radar.directionalFieldOfView/2) - ); - } - - void DisableAllRadars() - { - //rCount = 0; - UnlinkAllExternalRadars(); - - foreach(var radar in vessel.FindPartModulesImplementing()) - { - radar.DisableRadar(); - } - } - - - - public void SlaveTurrets() - { - foreach (var mtc in vessel.FindPartModulesImplementing()) - { - mtc.slaveTurrets = false; - } - - slaveTurrets = true; - } - - public void UnslaveTurrets() - { - foreach (var mtc in vessel.FindPartModulesImplementing()) - { - mtc.slaveTurrets = false; - } - - slaveTurrets = false; - - if(weaponManager) - { - weaponManager.slavingTurrets = false; - } - } - - void OnGUI() - { - if(drawGUI) - { - /* - if(BDArmorySettings.DRAW_DEBUG_LINES) - { - BDGUIUtils.DrawLineBetweenWorldPositions(referenceTransform.position, referenceTransform.position + (5 * referenceTransform.forward), 2, Color.blue); - BDGUIUtils.DrawLineBetweenWorldPositions(referenceTransform.position, referenceTransform.position + (5 * referenceTransform.right), 2, Color.red); - BDGUIUtils.DrawLineBetweenWorldPositions(referenceTransform.position, referenceTransform.position + (5 * referenceTransform.up), 2, Color.green); - } - */ - - for(int i = 0; i < lockedTargetIndexes.Count; i++) - { - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - string label = string.Empty; - if(i == activeLockedTargetIndex) - { - label += "Active: "; - } - if(!displayedTargets[lockedTargetIndexes[i]].vessel) - { - label += "data with no vessel"; - } - else - { - label += displayedTargets[lockedTargetIndexes[i]].vessel.vesselName; - } - GUI.Label(new Rect(20, 60 + (i * 26), 800, 446), label); - } - - TargetSignatureData lockedTarget = displayedTargets[lockedTargetIndexes[i]].targetData; - if(i == activeLockedTargetIndex) - { - if(weaponManager && lockedTarget.team == BDATargetManager.BoolToTeam(weaponManager.team)) - { - BDGUIUtils.DrawTextureOnWorldPos(lockedTarget.predictedPosition, BDArmorySettings.Instance.crossedGreenSquare, new Vector2(20, 20), 0); - } - else - { - BDGUIUtils.DrawTextureOnWorldPos(lockedTarget.predictedPosition, BDArmorySettings.Instance.openGreenSquare, new Vector2(20, 20), 0); - } - } - else - { - BDGUIUtils.DrawTextureOnWorldPos(lockedTarget.predictedPosition, BDArmorySettings.Instance.greenDiamondTexture, new Vector2(17, 17), 0); - } - } - - - string windowTitle = "Radar"; - radarWindowRect = GUI.Window(524141, radarWindowRect, RadarWindow, windowTitle, HighLogic.Skin.window); - BDGUIUtils.UseMouseEventInRect(radarWindowRect); - - if(linkWindowOpen && canReceiveRadarData) - { - linkWindowRect = new Rect(radarWindowRect.x - linkRectWidth, radarWindowRect.y + 16, linkRectWidth, 16 + (numberOfAvailableLinks * linkRectEntryHeight)); - LinkRadarWindow(); - - BDGUIUtils.UseMouseEventInRect(linkWindowRect); - } - - - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(800, 800, 800, 800), "radarCount: " + radarCount); - } - } - - - } - - - - - //GUI - - void RadarWindow(int windowID) - { - GUI.DragWindow(new Rect(0,0,radarScreenSize+(2*windowBorder), windowBorder+headerHeight)); - - if(!referenceTransform) return; - - Rect displayRect = new Rect(windowBorder, 12+windowBorder, radarScreenSize, radarScreenSize); - - - //============================== - GUI.BeginGroup(displayRect); - - - //bool omnidirectionalDisplay = (radarCount == 1 && linkedRadars[0].omnidirectional); - float directionalFieldOfView = omniDisplay ? 0 : availableRadars[0].directionalFieldOfView; - //bool linked = (radarCount > 1); - if(omniDisplay) - { - GUI.DrawTexture(radarRect, omniBgTexture, ScaleMode.StretchToFill, true); - - if(vessel.Landed) - { - GUI.Label(radarRect, " N", radarTopStyle); - } - - GUI.Label(new Rect(radarScreenSize*0.85f, radarScreenSize*0.1f, 60,24), (rIncrements[rangeIndex]/1000).ToString("0")+"km", distanceStyle); - - //my ship direction icon - float directionSize = 16; - Vector3 projectedVesselFwd = Vector3.ProjectOnPlane(vessel.ReferenceTransform.up, referenceTransform.up); - float dAngle = Vector3.Angle(projectedVesselFwd, referenceTransform.forward); - if(referenceTransform.InverseTransformVector(vessel.ReferenceTransform.up).x < 0) - { - dAngle = -dAngle; - } - GUIUtility.RotateAroundPivot(dAngle, radarRect.center); - GUI.DrawTexture(new Rect(radarRect.center.x - (directionSize / 2), radarRect.center.y - (directionSize / 2), directionSize, directionSize), BDArmorySettings.Instance.directionTriangleIcon, ScaleMode.StretchToFill, true); - GUI.matrix = Matrix4x4.identity; - - for(int i = 0; i < rCount; i++) - { - bool canScan = availableRadars[i].canScan; - bool canTrackWhileScan = availableRadars[i].canTrackWhileScan; - bool locked = availableRadars[i].locked; - float currentAngle = availableRadars[i].currentAngle; - - float radarAngle = VectorUtils.SignedAngle(projectedVesselFwd, Vector3.ProjectOnPlane(availableRadars[i].transform.up, referenceTransform.up), referenceTransform.right); - - if(canScan && availableRadars[i].vessel == vessel) - { - if((!locked || canTrackWhileScan)) - { - if(!availableRadars[i].omnidirectional) - { - currentAngle += radarAngle + dAngle; - } - else if(!vessel.Landed) - { - Vector3 north = VectorUtils.GetNorthVector(referenceTransform.position, vessel.mainBody); - float angleFromNorth = VectorUtils.SignedAngle(north, projectedVesselFwd, Vector3.Cross(north, vessel.upAxis)); - currentAngle += angleFromNorth; - } - - - GUIUtility.RotateAroundPivot(currentAngle, new Vector2(radarScreenSize / 2, radarScreenSize / 2)); - if(availableRadars[i].omnidirectional && radarCount == 1) - { - GUI.DrawTexture(radarRect, scanTexture, ScaleMode.StretchToFill, true); - } - else - { - BDGUIUtils.DrawRectangle(new Rect(radarRect.x + (radarRect.width / 2) - 1, radarRect.y, 2, radarRect.height / 2), new Color(0,1,0,0.35f)); - } - GUI.matrix = Matrix4x4.identity; - } - - //if linked and directional, draw FOV lines - if(!availableRadars[i].omnidirectional) - { - float fovAngle = availableRadars[i].directionalFieldOfView / 2; - float lineWidth = 2; - Rect verticalLineRect = new Rect(radarRect.center.x - (lineWidth / 2), 0, lineWidth, radarRect.center.y); - GUIUtility.RotateAroundPivot(dAngle + fovAngle + radarAngle, radarRect.center); - BDGUIUtils.DrawRectangle(verticalLineRect, new Color(0, 1, 0, 0.6f)); - GUI.matrix = Matrix4x4.identity; - GUIUtility.RotateAroundPivot(dAngle - fovAngle + radarAngle, radarRect.center); - BDGUIUtils.DrawRectangle(verticalLineRect, new Color(0, 1, 0, 0.4f)); - GUI.matrix = Matrix4x4.identity; - } - } - } - } - else - { - GUI.DrawTexture(radarRect, radialBgTexture, ScaleMode.StretchToFill, true); - GUI.Label(new Rect(5, 5, 60,24), (rIncrements[rangeIndex]/1000).ToString("0")+"km", distanceStyle); - - for(int i = 0; i < rCount; i++) - { - bool canScan = availableRadars[i].canScan; - bool locked = availableRadars[i].locked; - //float lockScanAngle = linkedRadars[i].lockScanAngle; - float currentAngle = availableRadars[i].currentAngle; - if(canScan) - { - float indicatorAngle = currentAngle;//locked ? lockScanAngle : currentAngle; - Vector2 scanIndicatorPos = RadarUtils.WorldToRadarRadial(referenceTransform.position + (Quaternion.AngleAxis(indicatorAngle, referenceTransform.up) * referenceTransform.forward), referenceTransform, radarRect, 5000, directionalFieldOfView / 2); - GUI.DrawTexture(new Rect(scanIndicatorPos.x - 7, scanIndicatorPos.y - 10, 14, 20), BDArmorySettings.Instance.greenDiamondTexture, ScaleMode.StretchToFill, true); - - if(locked && availableRadars[i].canTrackWhileScan) - { - Vector2 leftPos = RadarUtils.WorldToRadarRadial(referenceTransform.position + (Quaternion.AngleAxis(availableRadars[i].leftLimit, referenceTransform.up) * referenceTransform.forward), referenceTransform, radarRect, 5000, directionalFieldOfView / 2); - Vector2 rightPos = RadarUtils.WorldToRadarRadial(referenceTransform.position + (Quaternion.AngleAxis(availableRadars[i].rightLimit, referenceTransform.up) * referenceTransform.forward), referenceTransform, radarRect, 5000, directionalFieldOfView / 2); - float barWidth = 2; - float barHeight = 15; - Color origColor = GUI.color; - GUI.color = Color.green; - GUI.DrawTexture(new Rect(leftPos.x - barWidth, leftPos.y-barHeight, barWidth, barHeight), Texture2D.whiteTexture, ScaleMode.StretchToFill, true); - GUI.DrawTexture(new Rect(rightPos.x, rightPos.y-barHeight, barWidth, barHeight), Texture2D.whiteTexture, ScaleMode.StretchToFill, true); - GUI.color = origColor; - } - } - } - } - - //selector - if(showSelector) - { - float selectorSize = 18; - Rect selectorRect = new Rect(selectorPos.x - (selectorSize / 2), selectorPos.y - (selectorSize / 2), selectorSize, selectorSize); - Rect sLeftRect = new Rect(selectorRect.x, selectorRect.y, selectorSize / 6, selectorRect.height); - Rect sRightRect = new Rect(selectorRect.x + selectorRect.width - (selectorSize / 6), selectorRect.y, selectorSize / 6, selectorRect.height); - BDGUIUtils.DrawRectangle(sLeftRect, Color.green); - BDGUIUtils.DrawRectangle(sRightRect, Color.green); - } - - //missile data - if(lastMissile && lastMissile.targetAcquired) - { - Rect missileDataRect = new Rect (5, radarRect.height - 65, radarRect.width - 5, 60); - string missileDataString = lastMissile.GetShortName(); - missileDataString += "\nT-"+lastMissile.timeToImpact.ToString("0"); - - if (lastMissile.activeRadar && Mathf.Round(Time.time*3)%2==0) - { - missileDataString += "\nACTIVE"; - } - GUI.Label (missileDataRect, missileDataString, distanceStyle); - } - - - - //roll indicator - if(!vessel.Landed) - { - Vector3 localUp = vessel.ReferenceTransform.InverseTransformDirection(referenceTransform.up); - localUp = Vector3.ProjectOnPlane(localUp, Vector3.up).normalized; - float rollAngle = -Misc.SignedAngle(-Vector3.forward, localUp, Vector3.right); - GUIUtility.RotateAroundPivot(rollAngle, radarRect.center); - GUI.DrawTexture(radarRect, rollIndicatorTexture, ScaleMode.StretchToFill, true); - GUI.matrix = Matrix4x4.identity; - } - - - if(noData) - { - GUI.Label(radarRect, "NO DATA\n", lockStyle); - } - else - { - DrawDisplayedContacts(); - } - - - GUI.EndGroup(); - //========================================= - - - float buttonWidth = 70; - float gap = 2; - float buttonHeight = (controlsHeight / 2) - (2*gap); - float controlsStartY = headerHeight + radarScreenSize + windowBorder + windowBorder; - float controlsStartY2 = controlsStartY + buttonHeight + gap; - - Rect rangeUpRect = new Rect(windowBorder, controlsStartY, buttonWidth, buttonHeight); - if(GUI.Button(rangeUpRect, "Range +", HighLogic.Skin.button)) - { - IncreaseRange(); - } - Rect rangeDnRect = new Rect(rangeUpRect.x, controlsStartY2, rangeUpRect.width, rangeUpRect.height); - if(GUI.Button(rangeDnRect, "Range -", HighLogic.Skin.button)) - { - DecreaseRange(); - } - - Rect dataLinkRect = new Rect(rangeUpRect.x + gap + rangeUpRect.width, rangeUpRect.y, buttonWidth, buttonHeight); - if(canReceiveRadarData) - { - if(GUI.Button(dataLinkRect, "Data Link", linkWindowOpen ? HighLogic.Skin.box : HighLogic.Skin.button)) - { - if(linkWindowOpen) - { - CloseLinkRadarWindow(); - } - else - { - OpenLinkRadarWindow(); - } - } - } - else - { - Color oCol = GUI.color; - GUI.color = new Color(1, 1, 1, 0.35f); - GUI.Box(dataLinkRect, "Link N/A", HighLogic.Skin.button); - GUI.color = oCol; - } - - Rect lockModeCycleRect = new Rect(windowBorder + gap + buttonWidth + gap + buttonWidth, controlsStartY, buttonWidth, buttonHeight); - - if(this.locked) - { - if (GUI.Button (lockModeCycleRect, "Cycle Lock", HighLogic.Skin.button)) - { - CycleActiveLock(); - } - } - else if (!omniDisplay) //SCAN MODE SELECTOR - { - if(!locked) - { - string boresightToggle = availableRadars[0].boresightScan ? "Scan" : "Boresight"; - if(GUI.Button(lockModeCycleRect, boresightToggle, HighLogic.Skin.button)) - { - availableRadars[0].boresightScan = !availableRadars[0].boresightScan; - } - } - } - - Rect slaveRect = new Rect(lockModeCycleRect.x + gap + lockModeCycleRect.width, lockModeCycleRect.y, buttonWidth * 1.5f, buttonHeight); - //slave button - if (GUI.Button (slaveRect, slaveTurrets ? "Unslave Turrets" : "Slave Turrets", slaveTurrets ? HighLogic.Skin.box : HighLogic.Skin.button)) - { - if (slaveTurrets) - { - UnslaveTurrets (); - } else - { - SlaveTurrets (); - } - } - - //unlocking - Rect unlockRect = new Rect(lockModeCycleRect); - unlockRect.y += unlockRect.height + gap; - Rect unlockAllRect = new Rect(slaveRect); - unlockAllRect.y = unlockRect.y; - if(locked) - { - if(GUI.Button(unlockRect, "Unlock", HighLogic.Skin.button)) - { - UnlockCurrentTarget(); - } - - if(GUI.Button(unlockAllRect, "Unlock All", HighLogic.Skin.button)) - { - UnlockAllTargets(); - } - } - - - - Rect offRect = new Rect(slaveRect.x + gap + slaveRect.width, controlsStartY, 0, (2*buttonHeight)+gap); - offRect.width = radarWindowRect.width - offRect.x - windowBorder; - if(GUI.Button(offRect, "O\nF\nF", HighLogic.Skin.button)) - { - DisableAllRadars(); - } - } - - void LinkRadarWindow() - { - - GUI.Box(linkWindowRect, string.Empty, HighLogic.Skin.window); - - numberOfAvailableLinks = 0; - - GUI.BeginGroup(linkWindowRect); - - if(GUI.Button(new Rect(8, 8, 100, linkRectEntryHeight), "Refresh", HighLogic.Skin.button)) - { - RefreshAvailableLinks(); - } - numberOfAvailableLinks += 1.25f; - - foreach(var v in availableExternalVRDs) - { - if(v && v.vessel && v.vessel.loaded) - { - bool linked = externalVRDs.Contains(v); - GUIStyle style = linked ? HighLogic.Skin.box : HighLogic.Skin.button; - if(GUI.Button(new Rect(8, 8+(linkRectEntryHeight*numberOfAvailableLinks), linkRectWidth-16, linkRectEntryHeight), v.vessel.vesselName, style)) - { - if(linked) - { - //UnlinkRadar(v); - UnlinkVRD(v); - } - else - { - //LinkToRadar(v); - LinkVRD(v); - } - } - numberOfAvailableLinks++; - } - } - - - GUI.EndGroup(); - } - - public void RemoveDataFromRadar(ModuleRadar radar) - { - displayedTargets.RemoveAll(t => t.detectedByRadar == radar); - UpdateLockedTargets(); - } - - void UnlinkVRD(VesselRadarData vrd) - { - Debug.Log("Unlinking VRD: " + vrd.vessel.vesselName); - externalVRDs.Remove(vrd); - - List radarsToUnlink = new List(); - - foreach(var mr in availableRadars) - { - if(mr.vesselRadarData == vrd) - { - radarsToUnlink.Add(mr); - } - } - - foreach(var mr in radarsToUnlink) - { - Debug.Log(" - Unlinking radar: " + mr.radarName); - UnlinkRadar(mr); - } - - SaveExternalVRDVessels(); - } - - void UnlinkRadar(ModuleRadar mr) - { - if(mr && mr.vessel) - { - RemoveRadar(mr); - externalRadars.Remove(mr); - mr.RemoveExternalVRD(this); - - bool noMoreExternalRadar = true; - foreach(var rad in externalRadars) - { - if(rad.vessel == mr.vessel) - { - noMoreExternalRadar = false; - break; - } - } - - if(noMoreExternalRadar) - { - externalVRDs.Remove(mr.vesselRadarData); - } - } - else - { - externalRadars.RemoveAll(r => r == null); - } - } - - void RemoveEmptyVRDs() - { - externalVRDs.RemoveAll(vrd => vrd == null); - List vrdsToRemove = new List(); - foreach(var vrd in externalVRDs) - { - if(vrd.rCount == 0) - { - vrdsToRemove.Add(vrd); - } - } - - foreach(var vrd in vrdsToRemove) - { - externalVRDs.Remove(vrd); - } - } - - public void UnlinkDisabledRadar(ModuleRadar mr) - { - RemoveRadar(mr); - externalRadars.Remove(mr); - SaveExternalVRDVessels(); - } - - public void BeginWaitForUnloadedLinkedRadar(ModuleRadar mr, string vesselID) - { - UnlinkDisabledRadar(mr); - - if(waitingForVessels.Contains(vesselID)) - { - return; - } - - waitingForVessels.Add(vesselID); - SaveExternalVRDVessels(); - StartCoroutine(RecoverUnloadedLinkedVesselRoutine(vesselID)); - } - - List waitingForVessels; - IEnumerator RecoverUnloadedLinkedVesselRoutine(string vesselID) - { - while(true) - { - foreach(var v in BDATargetManager.LoadedVessels) - { - if(!v || !v.loaded || v==vessel) continue; - if(v.id.ToString() == vesselID) - { - VesselRadarData vrd = v.GetComponent(); - if(vrd) - { - waitingForVessels.Remove(vesselID); - StartCoroutine(LinkVRDWhenReady(vrd)); - yield break; - } - } - } - - yield return new WaitForSeconds(0.5f); - } - } - - IEnumerator LinkVRDWhenReady(VesselRadarData vrd) - { - while(!vrd.radarsReady || vrd.vessel.packed || vrd.radarCount < 1) - { - yield return null; - } - LinkVRD(vrd); - Debug.Log("Radar data link recovered: Local - " + vessel.vesselName + ", External - " + vrd.vessel.vesselName); - } - - public void UnlinkAllExternalRadars() - { - externalRadars.RemoveAll(r => r == null); - foreach(var eRad in externalRadars) - { - eRad.RemoveExternalVRD(this); - } - externalRadars.Clear(); - - externalVRDs.Clear(); - - availableRadars.RemoveAll(r => r == null); - availableRadars.RemoveAll(r => r.vessel != vessel); - rCount = availableRadars.Count; - - RefreshAvailableLinks(); - } - - void OpenLinkRadarWindow() - { - RefreshAvailableLinks(); - linkWindowOpen = true; - } - - void CloseLinkRadarWindow() - { - linkWindowOpen = false; - } - - void RefreshAvailableLinks() - { - if(!HighLogic.LoadedSceneIsFlight || !weaponManager) - { - //Debug.Log("tried refreshing links but weapon manager is null"); - return; - - } - - availableExternalVRDs = new List(); - foreach(var v in FlightGlobals.Vessels) - { - if(v.loaded && v!=vessel) - { - BDArmorySettings.BDATeams team = BDArmorySettings.BDATeams.None; - foreach(var mf in v.FindPartModulesImplementing()) - { - team = BDATargetManager.BoolToTeam(mf.team); - break; - } - if(team == BDATargetManager.BoolToTeam(weaponManager.team)) - { - VesselRadarData vrd = v.GetComponent(); - if(vrd && vrd.radarCount > 0) - { - availableExternalVRDs.Add(vrd); - } - } - } - } - } - - - - public void LinkVRD(VesselRadarData vrd) - { - if(!externalVRDs.Contains(vrd)) - { - externalVRDs.Add(vrd); - } - - - foreach(var mr in vrd.availableRadars) - { - LinkToRadar(mr); - } - - SaveExternalVRDVessels(); - } - - public void LinkToRadar(ModuleRadar mr) - { - if(!mr) - { - return; - } - - if(externalRadars.Contains(mr)) - { - return; - } - - externalRadars.Add(mr); - AddRadar(mr); - - mr.AddExternalVRD(this); - /* - linkedRadar = mr; - linkedVesselID = mr.vessel.id.ToString(); - linked = true; - if(mr.locked) - { - locked = true; - lockedTarget = mr.lockedTarget; - } - */ - //CloseLinkRadarWindow(); - } - - - public void AddRadarContact(ModuleRadar radar, TargetSignatureData contactData, bool _locked) - { - RadarDisplayData rData = new RadarDisplayData(); - rData.vessel = contactData.vessel; - - if(rData.vessel == vessel) - { - return; - } - - rData.signalPersistTime = radar.signalPersistTime; - rData.detectedByRadar = radar; - rData.locked = _locked; - rData.targetData = contactData; - rData.pingPosition = UpdatedPingPosition(contactData.position, radar); - - if(_locked) - { - radar.UpdateLockedTargetInfo(contactData); - } - - bool dontOverwrite = false; - - int replaceIndex = -1; - for(int i = 0; i < displayedTargets.Count; i++) - { - if(displayedTargets[i].vessel == rData.vessel) - { - if(displayedTargets[i].locked && !_locked) - { - dontOverwrite = true; - break; - } - - replaceIndex = i; - break; - } - } - - if(replaceIndex >= 0) - { - displayedTargets[replaceIndex] = rData; - //UpdateLockedTargets(); - return; - } - else if(dontOverwrite) - { - //UpdateLockedTargets(); - return; - } - else - { - displayedTargets.Add(rData); - UpdateLockedTargets(); - return; - } - } - - public void UnlockAllTargetsOfRadar(ModuleRadar radar) - { - //radar.UnlockTarget(); - displayedTargets.RemoveAll(t => t.detectedByRadar == radar); - UpdateLockedTargets(); - } - - /* - public void UnlockTargetAtPosition(Vector3 position) - { - displayedTargets.RemoveAll(t => Vector3.SqrMagnitude(t.targetData.position - position) < 10); - UpdateLockedTargets(); - } - */ - - public void RemoveVesselFromTargets(Vessel _vessel) - { - displayedTargets.RemoveAll(t => t.vessel == _vessel); - UpdateLockedTargets(); - } - - public void UnlockAllTargets() - { - foreach(var radar in weaponManager.radars) - { - radar.UnlockAllTargets(); - } - } - - public void UnlockCurrentTarget() - { - if(!locked) return; - - ModuleRadar rad = displayedTargets[lockedTargetIndexes[activeLockedTargetIndex]].detectedByRadar; - rad.UnlockTargetAt(rad.currentLockIndex); - } - - void CleanDisplayedContacts() - { - int count = displayedTargets.Count; - displayedTargets.RemoveAll(t => t.targetData.age > t.signalPersistTime*2); - if(count != displayedTargets.Count) - { - UpdateLockedTargets(); - } - } - - Vector2 UpdatedPingPosition(Vector3 worldPosition, ModuleRadar radar) - { - if(omniDisplay) - { - return RadarUtils.WorldToRadar(worldPosition, referenceTransform, radarRect, rIncrements[rangeIndex]); - } - else - { - return RadarUtils.WorldToRadarRadial(worldPosition, referenceTransform, radarRect, rIncrements[rangeIndex], radar.directionalFieldOfView / 2); - } - } - - bool pingPositionsDirty = true; - void DrawDisplayedContacts() - { - float myAlt = (float)vessel.altitude; - - bool drewLockLabel = false; - - bool lockDirty = false; - - for(int i = 0; i < displayedTargets.Count; i++) - { - if(displayedTargets[i].locked && locked) - { - TargetSignatureData lockedTarget = displayedTargets[i].targetData; - //LOCKED GUI - Vector2 pingPosition; - if(omniDisplay) - { - pingPosition = RadarUtils.WorldToRadar(lockedTarget.position, referenceTransform, radarRect, rIncrements[rangeIndex]); - } - else - { - pingPosition = RadarUtils.WorldToRadarRadial(lockedTarget.position, referenceTransform, radarRect, rIncrements[rangeIndex], displayedTargets[i].detectedByRadar.directionalFieldOfView / 2); - } - - //BDGUIUtils.DrawRectangle(new Rect(pingPosition.x-(4),pingPosition.y-(4),8, 8), Color.green); - float vAngle = Vector3.Angle(Vector3.ProjectOnPlane(lockedTarget.velocity, referenceTransform.up), referenceTransform.forward); - if(referenceTransform.InverseTransformVector(lockedTarget.velocity).x < 0) - { - vAngle = -vAngle; - } - GUIUtility.RotateAroundPivot(vAngle, pingPosition); - Rect pingRect = new Rect(pingPosition.x - (lockIconSize / 2), pingPosition.y - (lockIconSize / 2), lockIconSize, lockIconSize); - - - Texture2D txtr = (i == lockedTargetIndexes[activeLockedTargetIndex]) ? lockIconActive : lockIcon; - GUI.DrawTexture(pingRect, txtr, ScaleMode.StretchToFill, true); - GUI.matrix = Matrix4x4.identity; - GUI.Label(new Rect(pingPosition.x + (lockIconSize * 0.35f) + 2, pingPosition.y, 100, 24), (lockedTarget.altitude / 1000).ToString("0"), distanceStyle); - - - - if(!drewLockLabel) - { - GUI.Label(radarRect, "-LOCK-\n", lockStyle); - drewLockLabel = true; - - if(slaveTurrets) - { - GUI.Label(radarRect, "TURRETS\n\n", lockStyle); - } - } - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(pingPosition.x + (pingSize.x / 2), pingPosition.y, 100, 24), lockedTarget.signalStrength.ToString("0.0")); - } - - if(GUI.Button(pingRect, GUIContent.none, GUIStyle.none) && Time.time-guiInputTime > guiInputCooldown) - { - guiInputTime = Time.time; - if(i == lockedTargetIndexes[activeLockedTargetIndex]) - { - //UnlockTarget(displayedTargets[i].detectedByRadar); - //displayedTargets[i].detectedByRadar.UnlockTargetAtPosition(displayedTargets[i].targetData.position); - displayedTargets[i].detectedByRadar.UnlockTargetVessel(displayedTargets[i].vessel); - UpdateLockedTargets(); - lockDirty = true; - } - else - { - for(int x = 0; x < lockedTargetIndexes.Count; x++) - { - if(i == lockedTargetIndexes[x]) - { - activeLockedTargetIndex = x; - break; - } - } - - displayedTargets[i].detectedByRadar.SetActiveLock(displayedTargets[i].targetData); - - UpdateLockedTargets(); - } - } - - - //DLZ - if(!lockDirty) - { - int lTarInd = lockedTargetIndexes[activeLockedTargetIndex]; - - if(i == lTarInd && weaponManager && weaponManager.selectedWeapon != null) - { - if(weaponManager.selectedWeapon.GetWeaponClass() == WeaponClasses.Missile) - { - MissileLauncher currMissile = weaponManager.currentMissile; - if(currMissile.targetingMode == MissileLauncher.TargetingModes.Radar || currMissile.targetingMode == MissileLauncher.TargetingModes.Heat) - { - MissileLaunchParams dlz = MissileLaunchParams.GetDynamicLaunchParams(currMissile, lockedTarget.velocity, lockedTarget.predictedPosition); - float rangeToPixels = (1 / rIncrements[rangeIndex]) * radarRect.height; - float dlzWidth = 12; - float lineWidth = 2; - float dlzX = radarRect.width - dlzWidth - lineWidth; - - BDGUIUtils.DrawRectangle(new Rect(dlzX, 0, dlzWidth, radarRect.height), Color.black); - - Rect maxRangeVertLineRect = new Rect(radarRect.width - lineWidth, Mathf.Clamp(radarRect.height - (dlz.maxLaunchRange * rangeToPixels), 0, radarRect.height), lineWidth, Mathf.Clamp(dlz.maxLaunchRange * rangeToPixels, 0, radarRect.height)); - BDGUIUtils.DrawRectangle(maxRangeVertLineRect, Color.green); - - Rect maxRangeTickRect = new Rect(dlzX, maxRangeVertLineRect.y, dlzWidth, lineWidth); - BDGUIUtils.DrawRectangle(maxRangeTickRect, Color.green); - - Rect minRangeTickRect = new Rect(dlzX, Mathf.Clamp(radarRect.height - (dlz.minLaunchRange * rangeToPixels), 0, radarRect.height), dlzWidth, lineWidth); - BDGUIUtils.DrawRectangle(minRangeTickRect, Color.green); - - Rect rTrTickRect = new Rect(dlzX, Mathf.Clamp(radarRect.height - (dlz.rangeTr * rangeToPixels), 0, radarRect.height), dlzWidth, lineWidth); - BDGUIUtils.DrawRectangle(rTrTickRect, Color.green); - - Rect noEscapeLineRect = new Rect(dlzX, rTrTickRect.y, lineWidth, minRangeTickRect.y - rTrTickRect.y); - BDGUIUtils.DrawRectangle(noEscapeLineRect, Color.green); - - float targetDistIconSize = 16; - float targetDistY; - if(!omniDisplay) - { - targetDistY = pingPosition.y - (targetDistIconSize / 2); - } - else - { - targetDistY = radarRect.height - (Vector3.Distance(lockedTarget.predictedPosition, referenceTransform.position) * rangeToPixels) - (targetDistIconSize / 2); - } - - Rect targetDistanceRect = new Rect(dlzX - (targetDistIconSize / 2), targetDistY, targetDistIconSize, targetDistIconSize); - GUIUtility.RotateAroundPivot(90, targetDistanceRect.center); - GUI.DrawTexture(targetDistanceRect, BDArmorySettings.Instance.directionTriangleIcon, ScaleMode.StretchToFill, true); - GUI.matrix = Matrix4x4.identity; - } - } - - } - } - } - else - { - float minusAlpha = (Mathf.Clamp01((Time.time - displayedTargets[i].targetData.timeAcquired) / displayedTargets[i].signalPersistTime) * 2) - 1; - - //jamming - bool jammed = false; - if(displayedTargets[i].targetData.vesselJammer && displayedTargets[i].targetData.vesselJammer.jammerStrength > displayedTargets[i].targetData.signalStrength) - { - jammed = true; - } - - if(pingPositionsDirty) - { - //displayedTargets[i].pingPosition = UpdatedPingPosition(displayedTargets[i].targetData.position, displayedTargets[i].detectedByRadar); - RadarDisplayData newData = new RadarDisplayData(); - newData.detectedByRadar = displayedTargets[i].detectedByRadar; - newData.locked = displayedTargets[i].locked; - newData.pingPosition = UpdatedPingPosition(displayedTargets[i].targetData.position, displayedTargets[i].detectedByRadar); - newData.signalPersistTime = displayedTargets[i].signalPersistTime; - newData.targetData = displayedTargets[i].targetData; - newData.vessel = displayedTargets[i].vessel; - displayedTargets[i] = newData; - } - Vector2 pingPosition = displayedTargets[i].pingPosition; - - Rect pingRect; - //draw missiles and debris as dots - if((displayedTargets[i].targetData.targetInfo && displayedTargets[i].targetData.targetInfo.isMissile) || displayedTargets[i].targetData.team == BDArmorySettings.BDATeams.None) - { - float mDotSize = 6; - pingRect = new Rect(pingPosition.x - (mDotSize / 2), pingPosition.y - (mDotSize / 2), mDotSize, mDotSize); - Color origGUIColor = GUI.color; - GUI.color = Color.white - new Color(0, 0, 0, minusAlpha); - GUI.DrawTexture(pingRect, BDArmorySettings.Instance.greenDotTexture, ScaleMode.StretchToFill, true); - GUI.color = origGUIColor; - } - //draw contacts with direction indicator - else if(!jammed && (displayedTargets[i].detectedByRadar.showDirectionWhileScan) && displayedTargets[i].targetData.velocity.sqrMagnitude > 100) - { - pingRect = new Rect(pingPosition.x - (lockIconSize / 2), pingPosition.y - (lockIconSize / 2), lockIconSize, lockIconSize); - float vAngle = Vector3.Angle(Vector3.ProjectOnPlane(displayedTargets[i].targetData.velocity, referenceTransform.up), referenceTransform.forward); - if(referenceTransform.InverseTransformVector(displayedTargets[i].targetData.velocity).x < 0) - { - vAngle = -vAngle; - } - GUIUtility.RotateAroundPivot(vAngle, pingPosition); - Color origGUIColor = GUI.color; - GUI.color = Color.white - new Color(0, 0, 0, minusAlpha); - if(weaponManager && displayedTargets[i].targetData.team == BDATargetManager.BoolToTeam(weaponManager.team)) - { - GUI.DrawTexture(pingRect, friendlyContactIcon, ScaleMode.StretchToFill, true); - } - else - { - GUI.DrawTexture(pingRect, radarContactIcon, ScaleMode.StretchToFill, true); - } - - GUI.matrix = Matrix4x4.identity; - GUI.Label(new Rect(pingPosition.x + (lockIconSize * 0.35f) + 2, pingPosition.y, 100, 24), (displayedTargets[i].targetData.altitude / 1000).ToString("0"), distanceStyle); - GUI.color = origGUIColor; - } - else //draw contacts as rectangles - { - int drawCount = jammed ? 4 : 1; - pingRect = new Rect(pingPosition.x - (pingSize.x / 2), pingPosition.y - (pingSize.y / 2), pingSize.x, pingSize.y); - for(int d = 0; d < drawCount; d++) - { - Rect jammedRect = new Rect(pingRect); - Vector3 contactPosition = displayedTargets[i].targetData.position; - if(jammed) - { - //jamming - Vector3 jammedPosition = transform.position + ((displayedTargets[i].targetData.position - transform.position).normalized * UnityEngine.Random.Range(100, rIncrements[rangeIndex])); - float bearingVariation = Mathf.Clamp(Mathf.Pow(32000, 2) / (displayedTargets[i].targetData.position - transform.position).sqrMagnitude, 0, 80); - jammedPosition = transform.position + (Quaternion.AngleAxis(UnityEngine.Random.Range(-bearingVariation, bearingVariation), referenceTransform.up) * (jammedPosition - transform.position)); - if(omniDisplay) - { - pingPosition = RadarUtils.WorldToRadar(jammedPosition, referenceTransform, radarRect, rIncrements[rangeIndex]); - } - else - { - pingPosition = RadarUtils.WorldToRadarRadial(jammedPosition, referenceTransform, radarRect, rIncrements[rangeIndex], displayedTargets[i].detectedByRadar.directionalFieldOfView / 2); - } - - jammedRect = new Rect(pingPosition.x - (pingSize.x / 2), pingPosition.y - (pingSize.y / 2) - (pingSize.y / 3), pingSize.x, pingSize.y / 3); - contactPosition = jammedPosition; - } - - Color iconColor = Color.green; - float contactAlt = displayedTargets[i].targetData.altitude; - if(!omniDisplay && !jammed) - { - if(contactAlt - myAlt > 1000) - { - iconColor = new Color(0, 0.6f, 1f, 1); - } - else if(contactAlt - myAlt < -1000) - { - iconColor = new Color(1f, 0.68f, 0, 1); - } - } - - if(omniDisplay) - { - Vector3 localPos = referenceTransform.InverseTransformPoint(contactPosition); - localPos.y = 0; - float angleToContact = Vector3.Angle(localPos, Vector3.forward); - if(localPos.x < 0) angleToContact = -angleToContact; - GUIUtility.RotateAroundPivot(angleToContact, pingPosition); - } - - if(jammed || displayedTargets[i].targetData.team != BDATargetManager.BoolToTeam(weaponManager.team)) - { - BDGUIUtils.DrawRectangle(jammedRect, iconColor - new Color(0, 0, 0, minusAlpha)); - } - else - { - float friendlySize = 12; - Rect friendlyRect = new Rect(pingPosition.x - (friendlySize / 2), pingPosition.y - (friendlySize / 2), friendlySize, friendlySize); - Color origGuiColor = GUI.color; - GUI.color = iconColor - new Color(0, 0, 0, minusAlpha); - GUI.DrawTexture(friendlyRect, BDArmorySettings.Instance.greenDotTexture, ScaleMode.StretchToFill, true); - GUI.color = origGuiColor; - } - - GUI.matrix = Matrix4x4.identity; - } - } - - - if(GUI.Button(pingRect, GUIContent.none, GUIStyle.none) && Time.time-guiInputTime > guiInputCooldown) - { - guiInputTime = Time.time; - TryLockTarget(displayedTargets[i]); - } - - if(BDArmorySettings.DRAW_DEBUG_LABELS) - { - GUI.Label(new Rect(pingPosition.x + (pingSize.x / 2), pingPosition.y, 100, 24), displayedTargets[i].targetData.signalStrength.ToString("0.0")); - } - } - } - pingPositionsDirty = false; - } - - bool omniDisplay - { - get - { - return (radarCount > 1 || (radarCount == 1 && availableRadars[0].omnidirectional)); - } - } - - void UpdateInputs() - { - if(!vessel.isActiveVessel) - { - return; - } - - - if(BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_RIGHT)) - { - ShowSelector(); - SlewSelector(Vector2.right); - } - else if(BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_LEFT)) - { - ShowSelector(); - SlewSelector(-Vector2.right); - } - - if(BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_UP)) - { - ShowSelector(); - SlewSelector(-Vector2.up); - } - else if(BDInputUtils.GetKey(BDInputSettingsFields.RADAR_SLEW_DOWN)) - { - ShowSelector(); - SlewSelector(Vector2.up); - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_LOCK)) - { - if(showSelector) - { - TryLockViaSelector(); - } - ShowSelector(); - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_CYCLE_LOCK)) - { - if(locked) - { - CycleActiveLock(); - } - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_SCAN_MODE)) - { - if(!locked && radarCount > 0 && !omniDisplay) - { - availableRadars[0].boresightScan = !availableRadars[0].boresightScan; - } - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_TURRETS)) - { - if(slaveTurrets) - { - UnslaveTurrets(); - } - else - { - SlaveTurrets(); - } - } - - if(BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_RANGE_UP)) - { - IncreaseRange(); - } - else if(BDInputUtils.GetKeyDown(BDInputSettingsFields.RADAR_RANGE_DN)) - { - DecreaseRange(); - } - } - - void TryLockViaSelector() - { - bool found = false; - Vector3 closestPos = Vector3.zero; - float closestSqrMag = float.MaxValue; - for(int i = 0; i < displayedTargets.Count; i++) - { - float sqrMag = (displayedTargets[i].pingPosition - selectorPos).sqrMagnitude; - if(sqrMag < closestSqrMag) - { - if(sqrMag < Mathf.Pow(20, 2)) - { - closestPos = displayedTargets[i].targetData.predictedPosition; - found = true; - } - } - } - - if(found) - { - TryLockTarget(closestPos); - } - else if(closestSqrMag > Mathf.Pow(40, 2)) - { - UnlockCurrentTarget(); - } - - } - - void SlewSelector(Vector2 direction) - { - float rate = 150; - selectorPos += direction * rate * Time.deltaTime; - - if(!omniDisplay) - { - if(selectorPos.y > radarScreenSize * 0.975f) - { - if(rangeIndex > 0) - { - DecreaseRange(); - selectorPos.y = radarScreenSize * 0.75f; - } - } - else if(selectorPos.y < radarScreenSize * 0.025f) - { - if(rangeIndex < rIncrements.Length - 1) - { - IncreaseRange(); - selectorPos.y = radarScreenSize * 0.25f; - } - } - } - - selectorPos.y = Mathf.Clamp(selectorPos.y, 10, radarScreenSize - 10); - selectorPos.x = Mathf.Clamp(selectorPos.x, 10, radarScreenSize - 10); - } - - void ShowSelector() - { - if(!showSelector) - { - showSelector = true; - selectorPos = new Vector2(radarScreenSize / 2, radarScreenSize / 2); - } - } - - } -} - diff --git a/BahaTurret/ViewScanResults.cs b/BahaTurret/ViewScanResults.cs deleted file mode 100644 index 72274ae54..000000000 --- a/BahaTurret/ViewScanResults.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using UnityEngine; - -namespace BahaTurret -{ - public struct ViewScanResults - { - public bool foundMissile; - public bool foundHeatMissile; - public bool foundRadarMissile; - public bool foundAGM; - public bool firingAtMe; - public float missileThreatDistance; - public Vector3 threatPosition; - public Vessel threatVessel; - public MissileFire threatWeaponManager; - } -} - diff --git a/BahaTurret/WMTurretGroup.cs b/BahaTurret/WMTurretGroup.cs deleted file mode 100644 index 82bda0752..000000000 --- a/BahaTurret/WMTurretGroup.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace BahaTurret -{ - public class WMTurretGroup : MonoBehaviour - { - public enum TargetTypes{Air, Ground, Missiles, All} - - public List weapons; - - public bool guardMode = false; - public TargetTypes targetType = TargetTypes.All; - - - public void StartFiringOnTarget(Vessel targetVessel, float burstLength) - { - foreach(var weapon in weapons) - { - weapon.legacyTargetVessel = targetVessel; - weapon.autoFireTimer = Time.time; - weapon.autoFireLength = burstLength; - } - } - - public void ForceStopFiring() - { - foreach(var weapon in weapons) - { - weapon.autoFire = false; - weapon.legacyTargetVessel = null; - } - } - } -} - diff --git a/BahaTurret/bin/Debug/BahaTurret.dll b/BahaTurret/bin/Debug/BahaTurret.dll deleted file mode 100644 index c78f4879b..000000000 Binary files a/BahaTurret/bin/Debug/BahaTurret.dll and /dev/null differ diff --git a/BahaTurret/bin/Release/BahaTurret.dll b/BahaTurret/bin/Release/BahaTurret.dll deleted file mode 100644 index f19e285ee..000000000 Binary files a/BahaTurret/bin/Release/BahaTurret.dll and /dev/null differ diff --git a/BahaTurret/bin/Release/gpsTargets.cfg b/BahaTurret/bin/Release/gpsTargets.cfg deleted file mode 100644 index 499c01956..000000000 --- a/BahaTurret/bin/Release/gpsTargets.cfg +++ /dev/null @@ -1,4 +0,0 @@ -BDARMORY -{ - -} diff --git a/BahaTurret/obj/x86/Debug/BahaTurret.csproj.FileListAbsolute.txt b/BahaTurret/obj/x86/Debug/BahaTurret.csproj.FileListAbsolute.txt deleted file mode 100644 index 210eb6b42..000000000 --- a/BahaTurret/obj/x86/Debug/BahaTurret.csproj.FileListAbsolute.txt +++ /dev/null @@ -1,28 +0,0 @@ -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\BahaTurret.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\BahaTurret.pdb -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\Assembly-CSharp-firstpass.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\Assembly-CSharp.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\UnityEngine.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\System.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\System.Xml.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\TDx.TDxInput.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\TrackIRUnity.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\Mono.Cecil.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Debug\Mono.Security.dll -C:\Users\ferram4\BDArmory\BahaTurret\obj\x86\Debug\BahaTurret.csprojResolveAssemblyReference.cache -C:\Users\ferram4\BDArmory\BahaTurret\obj\x86\Debug\BahaTurret.dll -C:\Users\ferram4\BDArmory\BahaTurret\obj\x86\Debug\BahaTurret.pdb -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\BahaTurret.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\BahaTurret.pdb -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\Assembly-CSharp.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\UnityEngine.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\System.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\Assembly-CSharp-firstpass.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\System.Xml.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\TDx.TDxInput.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\TrackIRUnity.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\Mono.Cecil.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Debug\Mono.Security.dll -D:\Plugin Projects\BahaTurret\BahaTurret\obj\x86\Debug\BahaTurret.dll -D:\Plugin Projects\BahaTurret\BahaTurret\obj\x86\Debug\BahaTurret.pdb -D:\Plugin Projects\BahaTurret\BahaTurret\obj\x86\Debug\BahaTurret.csprojResolveAssemblyReference.cache diff --git a/BahaTurret/obj/x86/Debug/BahaTurret.csprojResolveAssemblyReference.cache b/BahaTurret/obj/x86/Debug/BahaTurret.csprojResolveAssemblyReference.cache deleted file mode 100644 index 0b0db671e..000000000 Binary files a/BahaTurret/obj/x86/Debug/BahaTurret.csprojResolveAssemblyReference.cache and /dev/null differ diff --git a/BahaTurret/obj/x86/Debug/BahaTurret.dll b/BahaTurret/obj/x86/Debug/BahaTurret.dll deleted file mode 100644 index c78f4879b..000000000 Binary files a/BahaTurret/obj/x86/Debug/BahaTurret.dll and /dev/null differ diff --git a/BahaTurret/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/BahaTurret/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache deleted file mode 100644 index 1ec5b3717..000000000 Binary files a/BahaTurret/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache and /dev/null differ diff --git a/BahaTurret/obj/x86/Release/BahaTurret.csproj.FileListAbsolute.txt b/BahaTurret/obj/x86/Release/BahaTurret.csproj.FileListAbsolute.txt deleted file mode 100644 index cde4bfc4d..000000000 --- a/BahaTurret/obj/x86/Release/BahaTurret.csproj.FileListAbsolute.txt +++ /dev/null @@ -1,29 +0,0 @@ -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\BahaTurret.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\System.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\System.Xml.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\TDx.TDxInput.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\TrackIRUnity.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\Mono.Cecil.dll -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\Mono.Security.dll -C:\Users\ferram4\BDArmory\BahaTurret\obj\x86\Release\BahaTurret.dll -C:\Users\ferram4\BDArmory\BahaTurret\obj\x86\Release\BahaTurret.csprojResolveAssemblyReference.cache -C:\Users\ferram4\BDArmory\BahaTurret\bin\Release\Assembly-CSharp-firstpass.dll -D:\Plugin Projects\BahaTurret\BahaTurret\obj\x86\Release\BahaTurret.csprojResolveAssemblyReference.cache -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\BahaTurret.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\Assembly-CSharp-firstpass.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\Assembly-CSharp.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\KSPCore.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\KSPUtil.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\UnityEngine.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\UnityEngine.UI.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\SaveUpgradePipeline.Core.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\TrackIRUnity.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\System.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\KSPAssets.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\System.Xml.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\Mono.Cecil.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\Vectrosity.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\TDx.TDxInput.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\Mono.Security.dll -D:\Plugin Projects\BahaTurret\BahaTurret\bin\Release\UnityEngine.xml -D:\Plugin Projects\BahaTurret\BahaTurret\obj\x86\Release\BahaTurret.dll diff --git a/BahaTurret/obj/x86/Release/BahaTurret.csprojResolveAssemblyReference.cache b/BahaTurret/obj/x86/Release/BahaTurret.csprojResolveAssemblyReference.cache deleted file mode 100644 index 2b4d953de..000000000 Binary files a/BahaTurret/obj/x86/Release/BahaTurret.csprojResolveAssemblyReference.cache and /dev/null differ diff --git a/BahaTurret/obj/x86/Release/BahaTurret.dll b/BahaTurret/obj/x86/Release/BahaTurret.dll deleted file mode 100644 index f19e285ee..000000000 Binary files a/BahaTurret/obj/x86/Release/BahaTurret.dll and /dev/null differ diff --git a/BahaTurret/obj/x86/Release/DesignTimeResolveAssemblyReferencesInput.cache b/BahaTurret/obj/x86/Release/DesignTimeResolveAssemblyReferencesInput.cache deleted file mode 100644 index ba2d820b8..000000000 Binary files a/BahaTurret/obj/x86/Release/DesignTimeResolveAssemblyReferencesInput.cache and /dev/null differ diff --git a/DamageCurves/ArmorCurve.txt b/DamageCurves/ArmorCurve.txt new file mode 100644 index 000000000..6b81a3eec --- /dev/null +++ b/DamageCurves/ArmorCurve.txt @@ -0,0 +1,18 @@ + 25 5 + 50 10 + 75 35 + 100 50 + 125 55 + 150 65 + 175 68 + 200 70 + 250 73 + 300 75 + 350 76 + 400 77 + 450 80 + 500 85 + +y\ =\ \ 80.58079\ +\frac{\ \left(-0.18818185\ -\ 80.5\right)}{1+\ \left(\frac{x}{\left(90\right)}\right)^{2.5}} + +y=(113*x)/(154+x) \ No newline at end of file diff --git a/README.md b/README.md index 94142deee..bb0d458ca 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,39 @@ BDArmory Gun turrets and other weapon systems for KSP -http://forum.kerbalspaceprogram.com/threads/85209-BDArmory +Original Author [BahamutoD](https://github.com/BahamutoD) + +Original [Forum link](http://forum.kerbalspaceprogram.com/threads/85209-BDArmory) + +Current [Forum link](https://forum.kerbalspaceprogram.com/index.php?/topic/184167-17x-bdarmory-continued-v130-05012019/) + +Current Maintainers: +- [PapaJoe](https://github.com/PapaJoesSoup) +- [jrodrigv](https://github.com/jrodrigv) +- [SpannerMonkey](https://github.com/SpannerMonkey) +- [gomker](https://github.com/gomker) +- [TheDog](https://github.com/TheDogKSP) +- [DoctorDavinci](https://github.com/DoctorDavinci) + +Contribution Guidance +======== +The BDA Team uses a Fork / Branch Workflow. If you would like to contribute to the project please use the following guides + +https://help.github.com/articles/fork-a-repo/ + +https://help.github.com/articles/creating-a-pull-request-from-a-fork/ + +We only accept Pull Request to the "dev" Branch. +It is preferred that any major changes use thier own separate branch with the naming convention Feature_ + +The "support" Branch is for bug fixes in between releases + +Finally the "master" branch is the latest release and considered production + +Licensing +======== +This mod for Kerbal Space Program was originally developed by Paolo Encarnacion (BahamutoD) and distributed under the license CC-BY-SA 2.0. +This mod is now being maintained in BahamutoD's absence by Joe Korinek (Papa_Joe) and continues to be distributed under the license CC-BY-SA 2.0. +Please read about the license at +https://creativecommons.org/licenses/by-sa/2.0/ +before attempting to modify and redistribute it. \ No newline at end of file