public void RemoveModifier(IStatsModifier modifier) { if (AbilityPower.RemoveStatModificator(modifier.AbilityPower)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Base_Ap, AbilityPower.BaseValue); appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Bonus_Ap_Flat, AbilityPower.FlatBonus); appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Bonus_Ap_Pct, AbilityPower.PercentBonus); } if (Armor.RemoveStatModificator(modifier.Armor)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Armor, Armor.Total); } if (ArmorPenetration.RemoveStatModificator(modifier.ArmorPenetration)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Armor_Pen_Flat, ArmorPenetration.FlatBonus); appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Armor_Pen_Pct, ArmorPenetration.PercentBonus); } if (AttackDamage.RemoveStatModificator(modifier.AttackDamage)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Base_Ad, AttackDamage.BaseValue); appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Bonus_Ad_Flat, AttackDamage.FlatBonus); appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Bonus_Ad_Pct, AttackDamage.PercentBonus); } if (AttackSpeedMultiplier.RemoveStatModificator(modifier.AttackSpeed)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Atks_multiplier, AttackSpeedMultiplier.Total); } if (CriticalChance.RemoveStatModificator(modifier.CriticalChance)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Crit_Chance, CriticalChance.Total); } GoldPerSecond.RemoveStatModificator(modifier.GoldPerSecond); if (HealthPoints.RemoveStatModificator(modifier.HealthPoints)) { appendStat(_updatedStats, MasterMask.MM_Four, FieldMask.FM4_MaxHp, HealthPoints.Total); } if (HealthRegeneration.RemoveStatModificator(modifier.HealthRegeneration)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Hp5, HealthRegeneration.Total); } if (LifeSteal.RemoveStatModificator(modifier.LifeSteel)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_LifeSteal, LifeSteal.Total); } if (MagicResist.RemoveStatModificator(modifier.MagicResist)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Magic_Armor, MagicResist.Total); } if (MagicPenetration.RemoveStatModificator(modifier.MagicPenetration)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Magic_Pen_Flat, MagicPenetration.FlatBonus); appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Magic_Pen_Pct, MagicPenetration.PercentBonus); } if (ManaPoints.RemoveStatModificator(modifier.ManaPoints)) { appendStat(_updatedStats, MasterMask.MM_Four, FieldMask.FM4_MaxMp, ManaPoints.Total); } if (ManaRegeneration.RemoveStatModificator(modifier.ManaRegeneration)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Mp5, ManaRegeneration.Total); } if (MoveSpeed.RemoveStatModificator(modifier.MoveSpeed)) { appendStat(_updatedStats, MasterMask.MM_Four, FieldMask.FM4_Speed, MoveSpeed.Total); } if (Range.RemoveStatModificator(modifier.Range)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Range, Range.Total); } if (Size.RemoveStatModificator(modifier.Size)) { appendStat(_updatedStats, MasterMask.MM_Four, FieldMask.FM4_ModelSize, Size.Total); } if (SpellVamp.RemoveStatModificator(modifier.SpellVamp)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_SpellVamp, SpellVamp.Total); } if (Tenacity.RemoveStatModificator(modifier.Tenacity)) { appendStat(_updatedStats, MasterMask.MM_Two, FieldMask.FM2_Tenacity, Tenacity.Total); } }
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; }