void CleanJammerList() { vessel = GetComponent <Vessel>(); if (!vessel) { Destroy(this); } jammers.RemoveAll(j => j == null); jammers.RemoveAll(j => j.vessel != vessel); using (var jam = VesselModuleRegistry.GetModules <ModuleECMJammer>(vessel).GetEnumerator()) while (jam.MoveNext()) { if (jam.Current == null) { continue; } if (jam.Current.jammerEnabled) { AddJammer(jam.Current); } } UpdateJammerStrength(); }
void VesselChange(Vessel v) { if (!v.isActiveVessel) { return; } bool moduleFound = false; using (var mtc = VesselModuleRegistry.GetModules <ModuleTargetingCamera>(v).GetEnumerator()) while (mtc.MoveNext()) { Debug.Log("[BDArmory.TargetingCamera]: Vessel switched to vessel with targeting camera. Refreshing camera state."); if (mtc.Current.cameraEnabled) { mtc.Current.DelayedEnable(); } else { mtc.Current.DisableCamera(); } moduleFound = true; } if (!moduleFound) { DisableCamera(); ModuleTargetingCamera.windowIsOpen = false; } }
void Awake() { if (!vessel) { vessel = GetComponent <Vessel>(); } 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 foreach (var otherInfo in vessel.gameObject.GetComponents <TargetInfo>()) { if (otherInfo != this) { Destroy(this); return; } } Team = null; var mf = VesselModuleRegistry.GetMissileFire(vessel, true); if (mf != null) { Team = mf.Team; weaponManager = mf; } else { var ml = VesselModuleRegistry.GetMissileBase(vessel, true); if (ml != null) { isMissile = true; MissileBaseModule = ml; Team = ml.Team; } } 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! } UpdateTargetPartList(); GameEvents.onVesselDestroy.Add(CleanFriendliesEngaging); }
public static void ForceDeadVessel(Vessel v) { Debug.Log("[BDArmory.Misc]: GM Killed Vessel " + v.GetDisplayName()); foreach (var missileFire in VesselModuleRegistry.GetModules <MissileFire>(v)) { PartExploderSystem.AddPartToExplode(missileFire.part); ExplosionFx.CreateExplosion(missileFire.part.transform.position, 0.2f, explModelPath, explSoundPath, ExplosionSourceType.Missile, 0, missileFire.part); } }
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 <TargetInfo>(); // vessel never been picked up on radar before: create new targetinfo record if (targetInfo == null) { targetInfo = v.gameObject.AddComponent <TargetInfo>(); } Team = null; if (targetInfo) // Always true, as we just set it? { Team = targetInfo.Team; } else { var mf = VesselModuleRegistry.GetMissileFire(v, true); if (mf != null) { Team = mf.Team; } } vesselJammer = v.gameObject.GetComponent <VesselECMJInfo>(); pingPosition = Vector2.zero; lockedByRadar = null; }
// Begin methods used for prioritizing targets public float TargetPriRange(MissileFire myMf) // 1- Target range normalized with max weapon range { if (myMf == null) { return(0); } float thisDist = (position - myMf.transform.position).magnitude; float maxWepRange = 0; using (var weapon = VesselModuleRegistry.GetModules <ModuleWeapon>(myMf.vessel).GetEnumerator()) while (weapon.MoveNext()) { if (weapon.Current == null) { continue; } maxWepRange = (weapon.Current.GetEngagementRangeMax() > maxWepRange) ? weapon.Current.GetEngagementRangeMax() : maxWepRange; } float targetPriRange = 1 - Mathf.Clamp(thisDist / maxWepRange, 0, 1); return(targetPriRange); }
public float MaxThrust(Vessel v) { float maxThrust = 0; float finalThrust = 0; using (var engines = VesselModuleRegistry.GetModules <ModuleEngines>(v).GetEnumerator()) while (engines.MoveNext()) { if (engines.Current == null) { continue; } if (!engines.Current.EngineIgnited) { continue; } MultiModeEngine mme = engines.Current.part.FindModuleImplementing <MultiModeEngine>(); if (IsAfterBurnerEngine(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 += Mathf.Max(0f, engineThrust * (engines.Current.thrustPercentage / 100f)); // Don't include negative thrust percentage drives (Danny2462 drives) as they don't contribute to the thrust. finalThrust += engines.Current.finalThrust; } return(maxThrust); }
private void UpdateList() { weaponManagers.Clear(); using (List <Vessel> .Enumerator v = FlightGlobals.Vessels.GetEnumerator()) while (v.MoveNext()) { if (v.Current == null || !v.Current.loaded || v.Current.packed) { continue; } if (VesselModuleRegistry.ignoredVesselTypes.Contains(v.Current.vesselType)) { continue; } var wms = VesselModuleRegistry.GetMissileFire(v.Current, true); if (wms != null) { if (!ColorAssignments.ContainsKey(wms.teamString)) { float rnd = UnityEngine.Random.Range(0f, 100f); ColorAssignments.Add(wms.Team.Name, Color.HSVToRGB((rnd / 100f), 1f, 1f)); } if (weaponManagers.TryGetValue(wms.Team.Name, out var teamManagers)) { teamManagers.Add(wms); } else { weaponManagers.Add(wms.Team.Name, new List <MissileFire> { wms }); } } } }
void OnGUI() { if ((HighLogic.LoadedSceneIsFlight && BDArmorySetup.GAME_UI_ENABLED && !MapView.MapIsEnabled && BDTISettings.TEAMICONS) || HighLogic.LoadedSceneIsFlight && !BDArmorySetup.GAME_UI_ENABLED && !MapView.MapIsEnabled && BDTISettings.TEAMICONS && BDTISettings.PERSISTANT) { Texture icon; float size = 40; using (List <Vessel> .Enumerator v = FlightGlobals.Vessels.GetEnumerator()) while (v.MoveNext()) { if (v.Current == null) { continue; } if (!v.Current.loaded || v.Current.packed || v.Current.isActiveVessel) { continue; } if (VesselModuleRegistry.ignoredVesselTypes.Contains(v.Current.vesselType)) { continue; } if (BDTISettings.MISSILES) { using (var ml = VesselModuleRegistry.GetModules <MissileBase>(v.Current).GetEnumerator()) while (ml.MoveNext()) { if (ml.Current == null) { continue; } if (ml.Current.MissileState != MissileBase.MissileStates.Idle && ml.Current.MissileState != MissileBase.MissileStates.Drop) { Vector3 sPos = FlightGlobals.ActiveVessel.vesselTransform.position; Vector3 tPos = v.Current.vesselTransform.position; Vector3 Dist = (tPos - sPos); Vector2 guiPos; string UIdist; string UoM; if (Dist.magnitude > 100) { if ((Dist.magnitude / 1000) >= 1) { UoM = "km"; UIdist = (Dist.magnitude / 1000).ToString("0.00"); } else { UoM = "m"; UIdist = Dist.magnitude.ToString("0.0"); } BDGUIUtils.DrawTextureOnWorldPos(v.Current.CoM, BDTISetup.Instance.TextureIconMissile, new Vector2(20, 20), 0); if (BDGUIUtils.WorldToGUIPos(ml.Current.vessel.CoM, out guiPos)) { Rect distRect = new Rect((guiPos.x - 12), (guiPos.y + 10), 100, 32); GUI.Label(distRect, UIdist + UoM, mIStyle); } } } } } if (BDTISettings.DEBRIS) { if (v.Current.vesselType != VesselType.Debris && !v.Current.isActiveVessel) { continue; } if (v.Current.LandedOrSplashed) { continue; } { Vector3 sPos = FlightGlobals.ActiveVessel.vesselTransform.position; Vector3 tPos = v.Current.vesselTransform.position; Vector3 Dist = (tPos - sPos); if (Dist.magnitude > 100) { BDGUIUtils.DrawTextureOnWorldPos(v.Current.CoM, BDTISetup.Instance.TextureIconDebris, new Vector2(20, 20), 0); } } } } int Teamcount = 0; using (var teamManagers = BDTISetup.Instance.weaponManagers.GetEnumerator()) while (teamManagers.MoveNext()) { Teamcount++; using (var wm = teamManagers.Current.Value.GetEnumerator()) while (wm.MoveNext()) { if (wm.Current == null) { continue; } Teamcolor = BDTISetup.Instance.ColorAssignments[wm.Current.Team.Name]; IconUIStyle.normal.textColor = Teamcolor; if (wm.Current.vessel.isActiveVessel) { if (BDTISettings.THREATICON) { if (wm.Current.currentTarget == null) { continue; } Vector3 sPos = FlightGlobals.ActiveVessel.CoM; Vector3 tPos = (wm.Current.currentTarget.Vessel.CoM); Vector3 RelPos = (tPos - sPos); if (RelPos.magnitude >= 100) { DrawThreatIndicator(wm.Current.vessel.CoM, wm.Current.currentTarget.Vessel.CoM, Teamcolor); } } } else { Vector3 selfPos = FlightGlobals.ActiveVessel.CoM; Vector3 targetPos = (wm.Current.vessel.CoM); Vector3 targetRelPos = (targetPos - selfPos); Vector2 guiPos; float distance; string UIdist; string UoM; string vName; string selectedWeapon = String.Empty; string AIstate = String.Empty; distance = targetRelPos.magnitude; if (distance >= 100) { if ((distance / 1000) >= 1) { UoM = "km"; UIdist = (distance / 1000).ToString("0.00"); } else { UoM = "m"; UIdist = distance.ToString("0.0"); } if ((wm.Current.vessel.vesselType == VesselType.Ship && !wm.Current.vessel.Splashed) || wm.Current.vessel.vesselType == VesselType.Plane) { icon = BDTISetup.Instance.TextureIconPlane; } else if (wm.Current.vessel.vesselType == VesselType.Base || wm.Current.vessel.vesselType == VesselType.Lander) { icon = BDTISetup.Instance.TextureIconBase; } else if (wm.Current.vessel.vesselType == VesselType.Rover) { icon = BDTISetup.Instance.TextureIconRover; } else if (wm.Current.vessel.vesselType == VesselType.Probe) { icon = BDTISetup.Instance.TextureIconProbe; } else if (wm.Current.vessel.vesselType == VesselType.Ship && wm.Current.vessel.Splashed) { icon = BDTISetup.Instance.TextureIconShip; if (wm.Current.vessel.vesselType == VesselType.Ship && wm.Current.vessel.altitude < -10) { icon = BDTISetup.Instance.TextureIconSub; } } else if (wm.Current.vessel.vesselType == VesselType.Debris) { icon = BDTISetup.Instance.TextureIconDebris; size = 20; IconUIStyle.normal.textColor = XKCDColors.Grey; Teamcolor = XKCDColors.Grey; } else { icon = BDTISetup.Instance.TextureIconGeneric; } DrawOnScreenIcon(wm.Current.vessel.CoM, icon, new Vector2((size * BDTISettings.ICONSCALE), (size * BDTISettings.ICONSCALE)), Teamcolor, true); if (BDTISettings.THREATICON) { if (wm.Current.currentTarget != null) { if (!wm.Current.currentTarget.Vessel.isActiveVessel) { DrawThreatIndicator(wm.Current.vessel.CoM, wm.Current.currentTarget.Vessel.CoM, Teamcolor); } } } if (BDGUIUtils.WorldToGUIPos(wm.Current.vessel.CoM, out guiPos)) { if (BDTISettings.VESSELNAMES) { vName = wm.Current.vessel.vesselName; Rect nameRect = new Rect((guiPos.x + (24 * BDTISettings.ICONSCALE)), guiPos.y - 4, 100, 32); GUI.Label(nameRect, vName, IconUIStyle); } if (BDTISettings.TEAMNAMES) { Rect teamRect = new Rect((guiPos.x + (16 * BDTISettings.ICONSCALE)), (guiPos.y - (19 * BDTISettings.ICONSCALE)), 100, 32); GUI.Label(teamRect, "Team: " + $"{wm.Current.Team.Name}", IconUIStyle); } if (BDTISettings.SCORE) { BDArmory.Control.ScoringData scoreData = null; int Score = 0; if (BDACompetitionMode.Instance.Scores.ContainsKey(wm.Current.vessel.vesselName)) { scoreData = BDACompetitionMode.Instance.Scores[wm.Current.vessel.vesselName]; Score = scoreData.Score; } if (VesselSpawner.Instance.vesselsSpawningContinuously) { if (VesselSpawner.Instance.continuousSpawningScores.ContainsKey(wm.Current.vessel.vesselName)) { Score += VesselSpawner.Instance.continuousSpawningScores[wm.Current.vessel.vesselName].cumulativeHits; } } Rect scoreRect = new Rect((guiPos.x + (16 * BDTISettings.ICONSCALE)), (guiPos.y + (14 * BDTISettings.ICONSCALE)), 100, 32); GUI.Label(scoreRect, "Score: " + Score, IconUIStyle); } if (BDTISettings.HEALTHBAR) { double hpPercent = 1; hpPercent = Mathf.Clamp((1 - ((wm.Current.totalHP - wm.Current.vessel.parts.Count) / wm.Current.totalHP)), 0, 1); if (hpPercent > 0) { Rect barRect = new Rect((guiPos.x - (32 * BDTISettings.ICONSCALE)), (guiPos.y + (30 * BDTISettings.ICONSCALE)), (64 * BDTISettings.ICONSCALE), 12); Rect healthRect = new Rect((guiPos.x - (30 * BDTISettings.ICONSCALE)), (guiPos.y + (32 * BDTISettings.ICONSCALE)), (60 * (float)hpPercent * BDTISettings.ICONSCALE), 8); //GUI.Label(healthRect, "Team: " + $"{wm.Current.Team.Name}", IconUIStyle); BDGUIUtils.DrawRectangle(barRect, XKCDColors.Grey); BDGUIUtils.DrawRectangle(healthRect, Color.HSVToRGB((85f * (float)hpPercent) / 255, 1f, 1f)); } Rect distRect = new Rect((guiPos.x - 12), (guiPos.y + (45 * BDTISettings.ICONSCALE)), 100, 32); GUI.Label(distRect, UIdist + UoM, IconUIStyle); } else { Rect distRect = new Rect((guiPos.x - 12), (guiPos.y + (20 * BDTISettings.ICONSCALE)), 100, 32); GUI.Label(distRect, UIdist + UoM, IconUIStyle); } if (BDTISettings.TELEMETRY) { selectedWeapon = "Using: " + wm.Current.selectedWeaponString; AIstate = "No AI"; if (wm.Current.AI != null) { AIstate = "Pilot " + wm.Current.AI.currentStatus; } Rect telemetryRect = new Rect((guiPos.x + (32 * BDTISettings.ICONSCALE)), guiPos.y + 32, 200, 32); GUI.Label(telemetryRect, selectedWeapon, IconUIStyle); Rect telemetryRect2 = new Rect((guiPos.x + (32 * BDTISettings.ICONSCALE)), guiPos.y + 48, 200, 32); GUI.Label(telemetryRect2, AIstate, IconUIStyle); if (wm.Current.isFlaring || wm.Current.isChaffing || wm.Current.isECMJamming) { Rect telemetryRect3 = new Rect((guiPos.x + (32 * BDTISettings.ICONSCALE)), guiPos.y + 64, 200, 32); GUI.Label(telemetryRect3, "Deploying Counter-Measures", IconUIStyle); } Rect SpeedRect = new Rect((guiPos.x - (96 * BDTISettings.ICONSCALE)), guiPos.y + 64, 100, 32); GUI.Label(SpeedRect, "Speed: " + wm.Current.vessel.speed.ToString("0.0") + "m/s", IconUIStyle); Rect RAltRect = new Rect((guiPos.x - (96 * BDTISettings.ICONSCALE)), guiPos.y + 80, 100, 32); GUI.Label(RAltRect, "Alt: " + wm.Current.vessel.altitude.ToString("0.0") + "m", IconUIStyle); Rect ThrottleRect = new Rect((guiPos.x - (96 * BDTISettings.ICONSCALE)), guiPos.y + 96, 100, 32); GUI.Label(ThrottleRect, "Throttle: " + Mathf.CeilToInt(wm.Current.vessel.ctrlState.mainThrottle * 100) + "%", IconUIStyle); } } } } } } } }
float MaxEngineAccel(float requestAccel, out float dragAccel) { float maxThrust = 0; float finalThrust = 0; multiModeEngines.Clear(); using (var engines = VesselModuleRegistry.GetModules <ModuleEngines>(vessel).GetEnumerator()) while (engines.MoveNext()) { if (engines.Current == null) { continue; } if (!engines.Current.EngineIgnited) { continue; } MultiModeEngine mme = engines.Current.part.FindModuleImplementing <MultiModeEngine>(); 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 += Mathf.Max(0f, engineThrust * (engines.Current.thrustPercentage / 100f)); // Don't include negative thrust percentage drives (Danny2462 drives) as they don't contribute to the thrust. finalThrust += engines.Current.finalThrust; } debugThrust = maxThrust; float vesselMass = vessel.GetTotalMass(); float accel = maxThrust / vesselMass; // This assumes that all thrust is in the same direction. //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; // This assumes that the acceleration from engines is in the same direction as the original possibleAccel. //use multimode afterburner for extra accel if lacking using (List <MultiModeEngine> .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(); } } } return(accel); }
public static void CheckDamageFX(Part part, float caliber, float penetrationFactor, bool explosivedamage, bool incendiary, string attacker, RaycastHit hitLoc) { if (!BDArmorySettings.BATTLEDAMAGE || BDArmorySettings.PAINTBALL_MODE) { return; } if (ProjectileUtils.IsIgnoredPart(part)) { return; // Ignore ignored parts. } double damageChance = Mathf.Clamp((BDArmorySettings.BD_DAMAGE_CHANCE * ((1 - part.GetDamagePercentage()) * 10) * (penetrationFactor / 2)), 0, 100); //more heavily damaged parts more likely to take battledamage if (BDArmorySettings.BD_TANKS) { if (part.HasFuel()) { var alreadyburning = part.GetComponentInChildren <FireFX>(); var rubbertank = part.FindModuleImplementing <ModuleSelfSealingTank>(); if (rubbertank != null) { if (rubbertank.SSTank && part.GetDamagePercentage() > 0.5f) { return; } } if (penetrationFactor > 1.2) { if (alreadyburning != null) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker); } else { BulletHitFX.AttachLeak(hitLoc, part, caliber, explosivedamage, incendiary, attacker); } } } } if (BDArmorySettings.BD_FIRES_ENABLED) { if (part.isBattery()) { var alreadyburning = part.GetComponentInChildren <FireFX>(); if (alreadyburning == null) { double Diceroll = UnityEngine.Random.Range(0, 100); if (explosivedamage) { Diceroll *= 0.33; } if (incendiary) { Diceroll *= 0.66; } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: Battery Dice Roll: " + Diceroll); } if (Diceroll <= BDArmorySettings.BD_DAMAGE_CHANCE) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker); } } } } //AmmoBins if (BDArmorySettings.BD_AMMOBINS && part.GetDamagePercentage() < 0.9f) //explosions have penetration of 0.5, should stop explosions phasing though parts from detonating ammo { var ammo = part.FindModuleImplementing <ModuleCASE>(); if (ammo != null) { ammo.SourceVessel = attacker; //moving this here so shots that destroy ammoboxes outright still report attacker if 'Ammo Explodes When Destroyed' is enabled if (penetrationFactor > 1.2) { double Diceroll = UnityEngine.Random.Range(0, 100); if (incendiary) { Diceroll *= 0.66; } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: Ammo TAC DiceRoll: " + Diceroll + "; needs: " + damageChance); } if (Diceroll <= (damageChance) && part.GetDamagePercentage() < 0.95f) { ammo.DetonateIfPossible(); } } if (!ammo.hasDetonated) //hit didn't destroy box { ammo.SourceVessel = ammo.vessel.GetName(); } } } //Propulsaion Damage if (BDArmorySettings.BD_PROPULSION) { if (part.isEngine() && part.GetDamagePercentage() < 0.95f) //first hit's free { foreach (var engine in part.GetComponentsInChildren <ModuleEngines>()) { bool isSRB = false; bool SRBFuelled = false; if (!engine.allowShutdown && engine.throttleLocked) { isSRB = true; using (IEnumerator <PartResource> resources = part.Resources.GetEnumerator()) while (resources.MoveNext()) { if (resources.Current == null) { continue; } if (resources.Current.resourceName.Contains("SolidFuel")) { if (resources.Current.amount > 1d) { SRBFuelled = true; } } } } if (engine.thrustPercentage > BDArmorySettings.BD_PROP_FLOOR) //engines take thrust damage per hit { //AP does bonus damage engine.thrustPercentage -= (((1 - part.GetDamagePercentage()) * (penetrationFactor / 2)) * BDArmorySettings.BD_PROP_DAM_RATE) * 10; //convert from damagepercent to thrustpercent Mathf.Clamp(engine.thrustPercentage, BDArmorySettings.BD_PROP_FLOOR, 100); //even heavily damaged engines will still put out something if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: engine thrust: " + engine.thrustPercentage); } engine.PlayFlameoutFX(true); /* * float enginelevel = engine.thrustPercentage; * if (BDArmorySettings.BD_BALANCED_THRUST) //need to poke this more later, not working properly * { * using (List<Part>.Enumerator pSym = part.symmetryCounterparts.GetEnumerator()) * while (pSym.MoveNext()) * { * if (pSym.Current == null) continue; * if (pSym.Current != part && pSym.Current.vessel == part.vessel) * { * var symEngine = pSym.Current.FindModuleImplementing<ModuleEngines>(); * if (symEngine != null) * { * symEngine.thrustPercentage = enginelevel; * } * } * } * } */ } if (part.GetDamagePercentage() < 0.75f || (part.GetDamagePercentage() < 0.82f && penetrationFactor > 2)) { var leak = part.GetComponentInChildren <FuelLeakFX>(); if (leak == null && !isSRB) //engine isn't a srb { BulletHitFX.AttachLeak(hitLoc, part, caliber, explosivedamage, incendiary, attacker); } } if (part.GetDamagePercentage() < 0.50f || (part.GetDamagePercentage() < 0.625f && penetrationFactor > 2)) { var alreadyburning = part.GetComponentInChildren <FireFX>(); if (isSRB) //srbs are steel tubes full of explosives; treat differently { if ((explosivedamage || incendiary) && SRBFuelled) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker); } } else { if (alreadyburning == null) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker, -1, 1, true); } } } if (part.GetDamagePercentage() < (BDArmorySettings.BD_PROP_FLAMEOUT / 100)) { if (engine.EngineIgnited) { if (isSRB) //SRB is lit, and casing integrity fails due to damage; boom { var Rupture = (ModuleCASE)part.AddModule("ModuleCASE"); Rupture.CASELevel = 0; Rupture.DetonateIfPossible(); } else { engine.PlayFlameoutFX(true); engine.Shutdown(); //kill a badly damaged engine and don't allow restart engine.allowRestart = false; } } } } } if (BDArmorySettings.BD_INTAKES) //intake damage { var intake = part.FindModuleImplementing <ModuleResourceIntake>(); if (intake != null) { float HEBonus = 0.7f; if (explosivedamage) { HEBonus = 1.4f; } if (incendiary) { HEBonus = 1.1f; } intake.intakeSpeed *= (1 - (((1 - part.GetDamagePercentage()) * HEBonus) * (BDArmorySettings.BD_PROP_DAM_RATE / 2))); //HE does bonus damage Mathf.Clamp((float)intake.intakeSpeed, 0, 99999); intake.area *= (1 - (((1 - part.GetDamagePercentage()) * HEBonus) / BDArmorySettings.BD_PROP_DAM_RATE)); //HE does bonus damage Mathf.Clamp((float)intake.area, 0.0005f, 99999); //even shredded intake ducting will still get some air to engines if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: Intake damage: Current Area: " + intake.area + "; Intake Speed: " + intake.intakeSpeed); } } } if (BDArmorySettings.BD_GIMBALS) //engine gimbal damage { var gimbal = part.FindModuleImplementing <ModuleGimbal>(); if (gimbal != null) { double HEBonus = 1; if (explosivedamage) { HEBonus = 1.4; } if (incendiary) { HEBonus = 1.25; } //gimbal.gimbalRange *= (1 - (((1 - part.GetDamagePercentatge()) * HEBonus) / BDArmorySettings.BD_PROP_DAM_RATE)); //HE does bonus damage double Diceroll = UnityEngine.Random.Range(0, 100); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: Gimbal DiceRoll: " + Diceroll); } if (Diceroll <= (BDArmorySettings.BD_DAMAGE_CHANCE * HEBonus)) { gimbal.enabled = false; gimbal.gimbalRange = 0; if (incendiary) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker, 20); } } } } } //Aero Damage if (BDArmorySettings.BD_AEROPARTS) { float HEBonus = 1; if (explosivedamage) { HEBonus = 2; //explosive rounds blow bigger holes in wings } Mathf.Clamp(penetrationFactor, 0.1f, 3); HEBonus /= penetrationFactor; //faster rounds punch cleaner holes float liftDam = ((caliber / 20000) * HEBonus) * BDArmorySettings.BD_LIFT_LOSS_RATE; if (part.GetComponent <ModuleLiftingSurface>() != null) { ModuleLiftingSurface wing; wing = part.GetComponent <ModuleLiftingSurface>(); //2x4m wing board = 2 Lift, 0.25 Lift/m2. 20mm round = 20*20=400/20000= 0.02 Lift reduced per hit, 100 rounds to reduce lift to 0. mind you, it only takes ~15 rounds to destroy the wing... if (wing.deflectionLiftCoeff > ((part.mass * 5) + liftDam)) //stock mass/lift ratio is 10; 0.2t wing has 2.0 lift; clamp lift lost at half { wing.deflectionLiftCoeff -= liftDam; } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: " + part.name + "took lift damage: " + liftDam + ", current lift: " + wing.deflectionLiftCoeff); } } if (part.GetComponent <ModuleControlSurface>() != null && part.GetDamagePercentage() > 0.125f) { ModuleControlSurface aileron; aileron = part.GetComponent <ModuleControlSurface>(); if (aileron.deflectionLiftCoeff > ((part.mass * 2.5f) + liftDam)) //stock ctrl surface mass/lift ratio is 5 { aileron.deflectionLiftCoeff -= liftDam; } if (BDArmorySettings.BD_CTRL_SRF) { int Diceroll = (int)UnityEngine.Random.Range(0f, 100f); if (explosivedamage) { HEBonus = 1.2f; } if (incendiary) { HEBonus = 1.1f; } if (Diceroll <= (BDArmorySettings.BD_DAMAGE_CHANCE * HEBonus)) { aileron.actuatorSpeed = 0; aileron.authorityLimiter = 0; aileron.ctrlSurfaceRange = 0; if (incendiary) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker, 10); } } } } } //Subsystems if (BDArmorySettings.BD_SUBSYSTEMS) { double Diceroll = UnityEngine.Random.Range(0, 100); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: Subsystem DiceRoll: " + Diceroll + "; needs: " + damageChance); } if (Diceroll <= (damageChance) && part.GetDamagePercentage() < 0.95f) { if (part.GetComponent <ModuleReactionWheel>() != null) //should have this be separate dice rolls, else a part with more than one of these will lose them all { ModuleReactionWheel SAS; //could have torque reduced per hit SAS = part.GetComponent <ModuleReactionWheel>(); part.RemoveModule(SAS); } if (part.GetComponent <ModuleRadar>() != null) { ModuleRadar radar; //would need to mod detection curve to degrade performance on hit radar = part.GetComponent <ModuleRadar>(); part.RemoveModule(radar); } if (part.GetComponent <ModuleAlternator>() != null) { ModuleAlternator alt; //damaging alternator is probably just petty. Could reduce output per hit alt = part.GetComponent <ModuleAlternator>(); part.RemoveModule(alt); } if (part.GetComponent <ModuleAnimateGeneric>() != null) { ModuleAnimateGeneric anim; anim = part.GetComponent <ModuleAnimateGeneric>(); // could reduce anim speed, open percent per hit part.RemoveModule(anim); } if (part.GetComponent <ModuleDecouple>() != null) { ModuleDecouple stage; stage = part.GetComponent <ModuleDecouple>(); //decouplers decouple stage.Decouple(); } if (part.GetComponent <ModuleECMJammer>() != null) { ModuleECMJammer ecm; ecm = part.GetComponent <ModuleECMJammer>(); //could reduce ecm strngth/rcs modifier part.RemoveModule(ecm); } if (part.GetComponent <ModuleGenerator>() != null) { ModuleGenerator gen; gen = part.GetComponent <ModuleGenerator>(); part.RemoveModule(gen); } if (part.GetComponent <ModuleResourceConverter>() != null) { ModuleResourceConverter isru; isru = part.GetComponent <ModuleResourceConverter>(); //could reduce efficiency, increase heat per hit part.RemoveModule(isru); } if (part.GetComponent <ModuleResourceConverter>() != null) { ModuleTurret turret; turret = part.GetComponent <ModuleTurret>(); //could reduce traverse speed, range per hit part.RemoveModule(turret); } if (part.GetComponent <ModuleTargetingCamera>() != null) { ModuleTargetingCamera cam; cam = part.GetComponent <ModuleTargetingCamera>(); // gimbal range?? part.RemoveModule(cam); } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: " + part.name + "took subsystem damage"); } if (Diceroll <= (damageChance * 2)) { if (incendiary) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker, 20); } } } } //Command parts if (BDArmorySettings.BD_COCKPITS && penetrationFactor > 1.2f && part.GetDamagePercentage() < 0.9f) //lets have this be triggered by penetrative damage, not blast splash { if (part.GetComponent <ModuleCommand>() != null) { double ControlDiceRoll = UnityEngine.Random.Range(0, 100); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: Command DiceRoll: " + ControlDiceRoll); } if (ControlDiceRoll <= (BDArmorySettings.BD_DAMAGE_CHANCE * 2)) { using (List <Part> .Enumerator craftPart = part.vessel.parts.GetEnumerator()) { using (var control = VesselModuleRegistry.GetModules <BDModulePilotAI>(part.vessel).GetEnumerator()) // FIXME should this be IBDAIControl? while (control.MoveNext()) { if (control.Current == null) { continue; } control.Current.evasionThreshold += 5; //pilot jitteriness increases control.Current.maxSteer *= 0.9f; if (control.Current.steerDamping > 0.625f) //damage to controls { control.Current.steerDamping -= 0.125f; } if (control.Current.dynamicSteerDampingPitchFactor > 0.625f) { control.Current.dynamicSteerDampingPitchFactor -= 0.125f; } if (control.Current.dynamicSteerDampingRollFactor > 0.625f) { control.Current.dynamicSteerDampingRollFactor -= 0.125f; } if (control.Current.dynamicSteerDampingYawFactor > 0.625f) { control.Current.dynamicSteerDampingYawFactor -= 0.125f; } } //GuardRange reduction to sim canopy/sensor damage? if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: " + part.name + "took command damage"); } } } } } if (part.protoModuleCrew.Count > 0 && penetrationFactor > 1.5f && part.GetDamagePercentage() < 0.95f) { if (BDArmorySettings.BD_PILOT_KILLS) { float PilotTAC = Mathf.Clamp((BDArmorySettings.BD_DAMAGE_CHANCE / part.mass), 0.01f, 100); //larger cockpits = greater volume = less chance any hit will pass through a region of volume containing a pilot float killchance = UnityEngine.Random.Range(0, 100); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.BattleDamageHandler]: Pilot TAC: " + PilotTAC + "; dice roll: " + killchance); } if (killchance <= PilotTAC) //add penetrationfactor threshold? hp threshold? { ProtoCrewMember crewMember = part.protoModuleCrew.FirstOrDefault(x => x != null); if (crewMember != null) { crewMember.UnregisterExperienceTraits(part); //crewMember.outDueToG = true; //implement temp KO to simulate wounding? crewMember.Die(); if (part.IsKerbalEVA()) { part.Die(); } else { part.RemoveCrewmember(crewMember); // sadly, I wasn't able to get the K.I.A. portrait working } //Vessel.CrewWasModified(part.vessel); //Debug.Log("[BDArmory.BattleDamageHandler]: " + crewMember.name + " was killed by damage to cabin!"); if (HighLogic.CurrentGame.Parameters.Difficulty.MissingCrewsRespawn) { crewMember.StartRespawnPeriod(); } //ScreenMessages.PostScreenMessage(crewMember.name + " killed by damage to " + part.vessel.name + part.partName + ".", 5.0f, ScreenMessageStyle.UPPER_LEFT); ScreenMessages.PostScreenMessage("Cockpit snipe on " + part.vessel.GetName() + "! " + crewMember.name + " killed!", 5.0f, ScreenMessageStyle.UPPER_LEFT); BDACompetitionMode.Instance.OnVesselModified(part.vessel); } } } } }