public static void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float penetrationfactor, float caliber, float projmass, float impactVelocity, float DmgMult, double distanceTraveled, bool explosive, bool hasRichocheted, Vessel sourceVessel, string name) { //hitting a vessel Part //No struts, they cause weird bugs :) -BahamutoD if (hitPart == null) { return; } if (hitPart.partInfo.name.Contains("Strut")) { return; } // Add decals if (BDArmorySettings.BULLET_HITS) { BulletHitFX.CreateBulletHit(hitPart, hit.point, hit, hit.normal, hasRichocheted, caliber, penetrationfactor); } // Apply damage float damage; damage = hitPart.AddBallisticDamage(projmass, caliber, multiplier, penetrationfactor, DmgMult, impactVelocity); if (BDArmorySettings.BATTLEDAMAGE) { BattleDamageHandler.CheckDamageFX(hitPart, caliber, penetrationfactor, explosive, sourceVessel.GetName(), hit); } // Debug.Log("DEBUG Ballistic damage to " + hitPart + ": " + damage + ", calibre: " + caliber + ", multiplier: " + multiplier + ", pen: " + penetrationfactor); // Update scoring structures ApplyScore(hitPart, sourceVessel, distanceTraveled, damage, name); }
private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float penetrationfactor) { if (OnlyVisual) { return; } //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); } }
void Update() { if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready && vessel != null && !vessel.packed) { if (this.part.temperature > 493) //autoignition temp of kerosene is 220 c { var isOnFire = part.GetComponentInChildren <FireFX>(); if (isOnFire == null) { string fireStarter; var vesselFire = part.vessel.GetComponentInChildren <FireFX>(); if (vesselFire != null) { fireStarter = vesselFire.SourceVessel; } else { fireStarter = part.vessel.GetName(); } Vector3 firePosition = part.transform.up * 10; Ray LoSRay = new Ray(transform.position, (transform.position + firePosition) - transform.position); RaycastHit hit; if (Physics.Raycast(LoSRay, out hit, 10, 9076737)) // only add fires to parts in LoS of blast { BulletHitFX.AttachFire(hit, part, 50, fireStarter); } Debug.Log("[SelfSealingTank] Fuel auto-ignition! " + part.name + " is on fire!"); } } } }
protected void CollisionEnter(Collision col) { if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory]: Missile Collided"); } if (TimeIndex > 2 && HasFired && col.collider.gameObject.GetComponentInParent <Part>().GetFireFX()) { ContactPoint contact = col.contacts[0]; Vector3 pos = contact.point; BulletHitFX.AttachFlames(pos, col.collider.gameObject.GetComponentInParent <Part>()); } if (HasExploded || !HasFired) { return; } if (DetonationDistanceState != DetonationDistanceStates.CheckingProximity) { return; } Debug.Log("[BDArmory]: Missile Collided - Triggering Detonation"); Detonate(); }
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); }
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); }
private void ApplyDamage(Part hitPart, RaycastHit hit) { //hitting a vessel Part //No struts, they cause weird bugs :) -BahamutoD if (hitPart == null) { return; } if (hitPart.partInfo.name.Contains("Strut")) { return; } float explDamage = 0; if (BDArmorySettings.BULLET_HITS) { BulletHitFX.CreateBulletHit(hitPart, hit.point, hit, hit.normal, false, 200, 3); } if (CASELevel == 2) { explDamage = 100; hitPart.AddDamage(explDamage); float armorToReduce = hitPart.GetArmorThickness() * 0.25f; hitPart.ReduceArmor(armorToReduce); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BD DEBUG]" + hitPart.name + "damaged, armor reduced by " + armorToReduce); } } else //CASE I { explDamage = (hitPart.Modules.GetModule <HitpointTracker>().GetMaxHitpoints() * 0.9f); explDamage = Mathf.Clamp(explDamage, 0, 600); hitPart.AddDamage(explDamage); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BD DEBUG]" + hitPart.name + "damaged for " + (hitPart.MaxDamage() * 0.9f)); } if (BDArmorySettings.BATTLEDAMAGE) { Misc.BattleDamageHandler.CheckDamageFX(hitPart, 200, 3, true, SourceVessel, hit); } } { var aName = SourceVessel; var tName = part.vessel.GetName(); if (aName != null && tName != null && aName != tName && BDACompetitionMode.Instance.Scores.ContainsKey(aName) && BDACompetitionMode.Instance.Scores.ContainsKey(tName)) { if (BDArmorySettings.REMOTE_LOGGING_ENABLED) { BDAScoreService.Instance.TrackDamage(aName, tName, explDamage); } var aData = BDACompetitionMode.Instance.Scores[aName]; aData.Score += 1; if (part.vessel.GetName() == "Pinata") { aData.PinataHits++; } var tData = BDACompetitionMode.Instance.Scores[tName]; tData.lastPersonWhoHitMe = aName; tData.lastHitTime = Planetarium.GetUniversalTime(); tData.everyoneWhoHitMe.Add(aName); // Track hits if (tData.hitCounts.ContainsKey(aName)) { ++tData.hitCounts[aName]; } else { tData.hitCounts.Add(aName, 1); } // Track damage if (tData.damageFromBullets.ContainsKey(aName)) { tData.damageFromBullets[aName] += explDamage; } else { tData.damageFromBullets.Add(aName, explDamage); } } } }
public static void CheckDamageFX(Part part, float caliber, float penetrationFactor, bool explosivedamage, string attacker, RaycastHit hitLoc) { if (!BDArmorySettings.BATTLEDAMAGE || BDArmorySettings.PAINTBALL_MODE) { return; } 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.66f) { return; } } if (penetrationFactor > 1.2) { if (alreadyburning != null) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker); } else { BulletHitFX.AttachLeak(hitLoc, part, caliber, explosivedamage, 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.66; } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BD Debug]: Battery Dice Roll: " + Diceroll); } if (Diceroll <= BDArmorySettings.BD_DAMAGE_CHANCE) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker); } } } } //AmmoBins if (BDArmorySettings.BD_AMMOBINS && penetrationFactor > 1.2 && 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) { double Diceroll = UnityEngine.Random.Range(0, 100); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BD Debug]: Ammo TAC DiceRoll: " + Diceroll + "; needs: " + damageChance); } if (Diceroll <= (damageChance) && part.GetDamagePercentage() < 0.95f) { ammo.SourceVessel = attacker; ammo.DetonateIfPossible(); } } } //Propulsaion Damage if (BDArmorySettings.BD_PROPULSION) { if (part.isEngine() && part.GetDamagePercentage() < 0.95f) //first hit's free { foreach (var engine in part.GetComponentsInChildren <ModuleEngines>()) { if (engine.thrustPercentage > 20) //engines take thrust damage per hit { //engine.maxThrust -= ((engine.maxThrust * 0.125f) / 100); // doesn't seem to adjust thrust; investigate //engine.thrustPercentage -= ((engine.maxThrust * 0.125f) / 100); //workaround hack engine.thrustPercentage -= (((1 - part.GetDamagePercentage()) * (penetrationFactor / 2)) * BDArmorySettings.BD_PROP_DAM_RATE); //AP does bonus damage Mathf.Clamp(engine.thrustPercentage, 15f, 100); //even heavily damaged engines will still put out something if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BD Debug]: engine thrust: " + engine.thrustPercentage); } /* * 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) { BulletHitFX.AttachLeak(hitLoc, part, caliber, explosivedamage, attacker); } } if (part.GetDamagePercentage() < 0.50f || (part.GetDamagePercentage() < 0.625f && penetrationFactor > 2)) { var alreadyburning = part.GetComponentInChildren <FireFX>(); if (alreadyburning == null) { BulletHitFX.AttachFire(hitLoc, part, caliber, attacker); } } if (part.GetDamagePercentage() < 0.25f) { if (engine.EngineIgnited) { 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; } intake.intakeSpeed *= (1 - (((1 - part.GetDamagePercentage()) * HEBonus) / BDArmorySettings.BD_PROP_DAM_RATE)); //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.0002f, 99999); //even shredded intake ducting will still get some air to engines if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BD Debug]: 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.5; } //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("[BD Debug]: Gimbal DiceRoll: " + Diceroll); } if (Diceroll <= (BDArmorySettings.BD_DAMAGE_CHANCE * HEBonus)) { gimbal.enabled = false; gimbal.gimbalRange = 0; } } } } //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("[BD DEBUG] " + 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 (Diceroll <= (BDArmorySettings.BD_DAMAGE_CHANCE * HEBonus)) { aileron.actuatorSpeed = 0; aileron.authorityLimiter = 0; aileron.ctrlSurfaceRange = 0; } } } } //Subsystems if (BDArmorySettings.BD_SUBSYSTEMS) { double Diceroll = UnityEngine.Random.Range(0, 100); if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BD Debug]: 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("[BD DEBUG] " + part.name + "took subsystem damage"); } } } //Command parts if (BDArmorySettings.BD_COCKPITS && penetrationFactor > 1 && 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("[BD Debug]: Command DiceRoll: " + ControlDiceRoll); } if (ControlDiceRoll <= (BDArmorySettings.BD_DAMAGE_CHANCE * 2)) { using (List <Part> .Enumerator craftPart = part.vessel.parts.GetEnumerator()) { using (List <BDModulePilotAI> .Enumerator control = part.vessel.FindPartModulesImplementing <BDModulePilotAI>().GetEnumerator()) while (control.MoveNext()) { if (control.Current == null) { continue; } control.Current.evasionThreshold += 10; //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("[BD DEBUG] " + part.name + "took command damage"); } } } } } if (part.protoModuleCrew.Count > 0 && penetrationFactor > 1 && 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("[BD Debug]: 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(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! " + crewMember.name + " killed!", 5.0f, ScreenMessageStyle.UPPER_LEFT); } } } } }
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; } // Add decals if (BDArmorySettings.BULLET_HITS) { BulletHitFX.CreateBulletHit(hitPart, hit.point, hit, hit.normal, hasRichocheted, caliber, penetrationfactor); } // Apply damage float damage; //if (explosive) //{ // damage = hitPart.AddBallisticDamage(bulletMass - tntMass, caliber, multiplier, penetrationfactor, bulletDmgMult, impactVelocity, hit, sourceVessel.GetName()); //} //why? The mass of HE filler isn't going to have disapeared before the bullet hits something, and if it has, it means there isn't a bullet left to hit things //else //{ damage = hitPart.AddBallisticDamage(bulletMass, caliber, multiplier, penetrationfactor, bulletDmgMult, impactVelocity); //} if (BDArmorySettings.BATTLEDAMAGE) { Misc.BattleDamageHandler.CheckDamageFX(hitPart, caliber, penetrationfactor, explosive, sourceVessel.GetName(), hit); } // Debug.Log("DEBUG Ballistic damage to " + hitPart + ": " + damage + ", calibre: " + caliber + ", multiplier: " + multiplier + ", pen: " + penetrationfactor); // Update scoring structures var aName = this.sourceVessel.GetName(); var tName = hitPart.vessel.GetName(); if (aName != null && tName != null && aName != tName && BDACompetitionMode.Instance.Scores.ContainsKey(aName) && BDACompetitionMode.Instance.Scores.ContainsKey(tName)) { //Debug.Log("[BDArmory]: Weapon from " + aName + " damaged " + tName); if (BDArmorySettings.REMOTE_LOGGING_ENABLED) { BDAScoreService.Instance.TrackHit(aName, tName, bullet.name, distanceTraveled); BDAScoreService.Instance.TrackDamage(aName, tName, damage); } // update scoring structure on attacker { var aData = BDACompetitionMode.Instance.Scores[aName]; aData.Score += 1; // keep track of who shot who for point keeping // competition logic for 'Pinata' mode - this means a pilot can't be named 'Pinata' if (hitPart.vessel.GetName() == "Pinata") { aData.PinataHits++; } } // update scoring structure on the defender. { var tData = BDACompetitionMode.Instance.Scores[tName]; tData.lastPersonWhoHitMe = aName; tData.lastHitTime = Planetarium.GetUniversalTime(); tData.everyoneWhoHitMe.Add(aName); // Track hits if (tData.hitCounts.ContainsKey(aName)) { ++tData.hitCounts[aName]; } else { tData.hitCounts.Add(aName, 1); } // Track damage if (tData.damageFromBullets.ContainsKey(aName)) { tData.damageFromBullets[aName] += damage; } else { tData.damageFromBullets.Add(aName, damage); } } } }
void FixedUpdate() { float distanceFromStartSqr = (transform.position - startPosition).sqrMagnitude; 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.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 (distanceFromStartSqr > maxDistance * maxDistance) { //GameObject.Destroy(gameObject); KillBullet(); return; } if (collisionEnabled) { float dist = initialSpeed * TimeWarp.fixedDeltaTime; Ray ray = new Ray(prevPosition, currPosition - prevPosition); RaycastHit hit; try { if (Physics.Raycast(ray, out hit, dist, 688129)) { bool penetrated = true; bool hitEva = false; Part hitPart = null; //determine when bullet collides with a target try { // Look for any Kerbal first. The part, KerbalEVA, is functionally similar to regular parts. KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); hitPart = eva ? eva.part : hit.collider.gameObject.GetComponentInParent <Part>(); hitEva = eva; } catch (NullReferenceException) { } // Need to make sure Kerbals don't get armor. BDArmor armor = hitEva ? null : BDArmor.GetArmor(hit.collider, hitPart); ArmorPenetration.BulletPenetrationData armorData = new ArmorPenetration.BulletPenetrationData(ray, hit); ArmorPenetration.DoPenetrationRay(armorData, bullet.positiveCoefficient); float penetration = bullet.penetration.Evaluate(Mathf.Sqrt(distanceFromStartSqr)) / 1000; bool fulllyPenetrated = penetration * leftPenetration > ((armor == null) ? 1f : armor.EquivalentThickness) * armorData.armorThickness; Vector3 finalDirect = Vector3.Lerp(ray.direction, -hit.normal, bullet.positiveCoefficient); if (fulllyPenetrated) { currentVelocity = finalDirect * currentVelocity.magnitude * leftPenetration; } else { currPosition = hit.point; bulletTrail.SetPosition(1, currPosition); } 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////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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(-75f, 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 * bulletDmgMult ; //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 (fulllyPenetrated) { 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("[BDArmory]: Hit! damage applied: " + heatDamage); //debugging stuff } if (hitPart.vessel != sourceVessel) { hitPart.AddDamage(heatDamage); } 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.AddDamage(overKillHeatDamage / (hitPart.parent.crashTolerance * hitPart.parent.mass)); for (int i = 0; i < hitPart.children.Count; i++) { hitPart.children[i].AddDamage(overKillHeatDamage / hitPart.children[i].crashTolerance); } } else { overKillHeatDamage /= numConnectedParts; for (int i = 0; i < hitPart.children.Count; i++) { hitPart.children[i].AddDamage(overKillHeatDamage / hitPart.children[i].crashTolerance); } } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////[panzer1b] HEAT BASED DAMAGE CODE END//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //hitting a Building DestructibleBuilding hitBuilding = null; try { hitBuilding = hit.collider.gameObject.GetComponentUpwards <DestructibleBuilding>(); } 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_LABELS) { Debug.Log("[BDArmory]: bullet hit destructible building! Damage: " + (damageToBuilding).ToString("0.00") + ", total Damage: " + hitBuilding.Damage); } } } if (hitPart == null || (hitPart != null && hitPart.vessel != sourceVessel)) { if (!penetrated && !hasBounced && !fulllyPenetrated) { //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); } if (armor != null && (penetration * leftPenetration > armor.outerArmorThickness / 1000 * armor.EquivalentThickness || fulllyPenetrated)) { switch (armor.explodeMode) { case BDArmor.ExplodeMode.Always: armor.CreateExplosion(hitPart); break; case BDArmor.ExplodeMode.Dynamic: float probability = CalculateExplosionProbability(hitPart); if (probability > 0.1f) { armor.CreateExplosion(hitPart); } break; case BDArmor.ExplodeMode.Never: break; } } if (fulllyPenetrated) { leftPenetration -= armorData.armorThickness / penetration; transform.position = armorData.hitResultOut.point; flightTimeElapsed -= Time.fixedDeltaTime; prevPosition = transform.position; FixedUpdate(); return; } else { KillBullet(); return; } } } } } catch (NullReferenceException e) // Exception handling { Debug.Log("[BDArmory]: Ran afoul of exception filter\n" + e.StackTrace); } } if (bulletType == PooledBulletTypes.Explosive && airDetonation && distanceFromStartSqr > detonationRange * 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; }
void Detonate(Vector3 pos, bool missed) { if (!missed) { if (tntMass > 0) { Vector3 direction = default(Vector3); if (shaped) { direction = (pos + rb.velocity * Time.deltaTime).normalized; } if (gravitic) { using (var hitsEnu = Physics.OverlapSphere(transform.position, blastRadius, 557057).AsEnumerable().GetEnumerator()) { while (hitsEnu.MoveNext()) { if (hitsEnu.Current == null) { continue; } Part partHit = hitsEnu.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } float distance = Vector3.Distance(transform.position, partHit.transform.position); if (gravitic) { if (partHit.mass > 0) { var ME = partHit.vessel.rootPart.FindModuleImplementing <ModuleMassAdjust>(); if (ME == null) { ME = (ModuleMassAdjust)partHit.vessel.rootPart.AddModule("ModuleMassAdjust"); } ME.massMod += (massMod * (1 - (distance / blastRadius))); //this way craft at edge of blast might only get disabled instead of bricked ME.duration += (BDArmorySettings.WEAPON_FX_DURATION * (1 - (distance / blastRadius))); //can bypass EMP damage cap } } } } } if (incendiary) { for (int f = 0; f < 20; f++) //throw 20 random raytraces out in a sphere and see what gets tagged { Ray LoSRay = new Ray(transform.position, VectorUtils.GaussianDirectionDeviation(transform.forward, 170)); RaycastHit hit; if (Physics.Raycast(LoSRay, out hit, blastRadius * 1.2f, 9076737)) // only add fires to parts in LoS of blast { KerbalEVA eva = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>(); Part p = eva ? eva.part : hit.collider.gameObject.GetComponentInParent <Part>(); float distance = Vector3.Distance(transform.position, hit.point); if (p != null) { BulletHitFX.AttachFire(hit, p, caliber, sourceVesselName, BDArmorySettings.WEAPON_FX_DURATION * (1 - (distance / blastRadius)), 1, false, true); //else apply fire to occluding part if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[BDArmory.Rocket]: Applying fire to " + p.name + " at distance " + distance + "m, for " + BDArmorySettings.WEAPON_FX_DURATION * (1 - (distance / blastRadius)) + " seconds"); } ; } } if (BDArmorySettings.DRAW_DEBUG_LABELS) { Debug.Log("[Rocket] incendiary raytrace: " + hit.point.x + "; " + hit.point.y + "; " + hit.point.z); } } } if (concussion || EMP || choker) { using (var hitsEnu = Physics.OverlapSphere(transform.position, 25, 557057).AsEnumerable().GetEnumerator()) { var craftHit = new HashSet <Vessel>(); while (hitsEnu.MoveNext()) { if (hitsEnu.Current == null) { continue; } if (hitsEnu.Current.gameObject == FlightGlobals.currentMainBody.gameObject) { continue; // Ignore terrain hits. } Part partHit = hitsEnu.Current.GetComponentInParent <Part>(); if (partHit == null) { continue; } if (ProjectileUtils.IsIgnoredPart(partHit)) { continue; // Ignore ignored parts. } if (craftHit.Contains(partHit.vessel)) { continue; // Don't hit the same craft multiple times. } craftHit.Add(partHit.vessel); float Distance = Vector3.Distance(partHit.transform.position, this.transform.position); if (partHit != null) { if (concussion && partHit.mass > 0) { partHit.rb.AddForceAtPosition((partHit.transform.position - this.transform.position).normalized * impulse, partHit.transform.position, ForceMode.Acceleration); } if (EMP) { var MDEC = partHit.vessel.rootPart.FindModuleImplementing <ModuleDrainEC>(); if (MDEC == null) { MDEC = (ModuleDrainEC)partHit.vessel.rootPart.AddModule("ModuleDrainEC"); } MDEC.incomingDamage += ((25 - Distance) * 5); //this way craft at edge of blast might only get disabled instead of bricked MDEC.softEMP = false; //can bypass EMP damage cap } if (choker) { var ash = partHit.vessel.rootPart.FindModuleImplementing <ModuleDrainIntakes>(); if (ash == null) { ash = (ModuleDrainIntakes)partHit.vessel.rootPart.AddModule("ModuleDrainIntakes"); } ash.drainDuration += BDArmorySettings.WEAPON_FX_DURATION * (1 - (Distance / 25)); //reduce intake knockout time based on distance from epicenter } } } } ExplosionFx.CreateExplosion(pos, tntMass, explModelPath, explSoundPath, ExplosionSourceType.Bullet, caliber, null, sourceVesselName, null, direction, true); } else { ExplosionFx.CreateExplosion(pos, tntMass, explModelPath, explSoundPath, ExplosionSourceType.Bullet, caliber, null, sourceVesselName, null, direction); } } } // needs to be Explosiontype Bullet since missile only returns Module MissileLauncher gameObject.SetActive(false); }