static void OptimizeEndPoints4(Vector3[] block, ref Vector3[] dxtPoints, ref uint indices) { float alpha2_sum = 0.0f; float beta2_sum = 0.0f; float alphabeta_sum = 0.0f; Vector3 alphax_sum = Vector3.Zero; Vector3 betax_sum = Vector3.Zero; for (int i = 0; i < 16; ++i) { uint bits = indices >> (2 * i); float beta = (float)(bits & 1); if ((bits & 2) > 0) { beta = (1 + beta) / 3.0f; } float alpha = 1.0f - beta; alpha2_sum += alpha * alpha; beta2_sum += beta * beta; alphabeta_sum += alpha * beta; alphax_sum += alpha * block[i]; betax_sum += beta * block[i]; } float denom = alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum; if (NvMath.Equal(denom, 0.0f)) { return; } float factor = 1.0f / denom; Vector3 a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor; Vector3 b = (betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor; a = Vector3.Clamp(a, 0, 255); b = Vector3.Clamp(b, 0, 255); //UInt16 color0 = roundAndExpand(ref a); //UInt16 color1 = roundAndExpand(ref b); //if (color0 < color1) //{ // NvMath.swap(ref a, ref b); // NvMath.swap(ref color0, ref color1); //} //indices = computeIndices4(block, a, b); dxtPoints[0] = a; dxtPoints[1] = b; }
public static void Postfix(ToHit __instance, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot, ref string __result) { string str = string.Empty; bool flag = lofLevel < LineOfFireLevel.LOFObstructed && (CustomAmmoCategories.getIndirectFireCapable(weapon)); float weaponDirectFireModifier = CustomAmmoCategories.getDirectFireModifier(weapon); if (flag == false) { //CustomAmmoCategoriesLog.Log.LogWrite(attacker.DisplayName + " has LOS on " + target.DisplayName + ". Apply DirectFireModifier " + weaponDirectFireModifier + "\n"); if (!NvMath.FloatIsNearZero(weaponDirectFireModifier)) { __result = string.Format("{0}WEAPON-DIRECT-FIRE {1:+#;-#}; ", (object)__result, (object)(int)weaponDirectFireModifier); } } CombatGameState combat = (CombatGameState)typeof(ToHit).GetField("combat", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); return; }
// Takes a normalized color in [0, 255] range and returns static ushort RoundAndExpand(ref Vector3 v) { uint r = (uint)Math.Floor(NvMath.Clamp(v.X * (31.0f / 255.0f), 0.0f, 31.0f)); uint g = (uint)Math.Floor(NvMath.Clamp(v.Y * (31.0f / 255.0f), 0.0f, 31.0f)); uint b = (uint)Math.Floor(NvMath.Clamp(v.Z * (31.0f / 255.0f), 0.0f, 31.0f)); float r0 = (float)(((r + 0) << 3) | ((r + 0) >> 2)); float r1 = (float)(((r + 1) << 3) | ((r + 1) >> 2)); if (Math.Abs(v.X - r1) < Math.Abs(v.X - r0)) { r = Math.Min(r + 1, 31U); } float g0 = (float)(((g + 0) << 3) | ((g + 0) >> 2)); float g1 = (float)(((g + 1) << 3) | ((g + 1) >> 2)); if (Math.Abs(v.Y - g1) < Math.Abs(v.Y - g0)) { g = Math.Min(g + 1, 31U); } float b0 = (float)(((b + 0) << 3) | ((b + 0) >> 2)); float b1 = (float)(((b + 1) << 3) | ((b + 1) >> 2)); if (Math.Abs(v.Z - b1) < Math.Abs(v.Z - b0)) { b = Math.Min(b + 1, 31U); } ushort w = (ushort)((b << 10) | (g << 5) | r); r = (r << 3) | (r >> 2); g = (g << 3) | (g >> 2); b = (b << 3) | (b >> 2); v = new Vector3((float)r, (float)g, (float)b); return(w); }
public static bool Prefix(LineOfSight __instance, ref LineOfFireLevel __result, CombatGameState ___Combat, AbstractActor source, Vector3 sourcePosition, ICombatant target, Vector3 targetPosition, Quaternion targetRotation, out Vector3 collisionWorldPos) { Mod.Log.Trace?.Write($"LOS:GLOFU entered. "); Vector3 forward = targetPosition - sourcePosition; forward.y = 0f; Quaternion rotation = Quaternion.LookRotation(forward); Vector3[] lossourcePositions = source.GetLOSSourcePositions(sourcePosition, rotation); Vector3[] lostargetPositions = target.GetLOSTargetPositions(targetPosition, targetRotation); List <AbstractActor> allActors = new List <AbstractActor>(___Combat.AllActors); allActors.Remove(source); AbstractActor abstractActor = target as AbstractActor; string targetedBuildingGuid = null; if (abstractActor != null) { allActors.Remove(abstractActor); } else { targetedBuildingGuid = target.GUID; } LineSegment lineSegment = new LineSegment(sourcePosition, targetPosition); // Sort the target actors by distance from the source allActors.Sort((AbstractActor x, AbstractActor y) => Vector3.Distance(x.CurrentPosition, sourcePosition).CompareTo(Vector3.Distance(y.CurrentPosition, sourcePosition)) ); float targetPositionDistance = Vector3.Distance(sourcePosition, targetPosition); for (int i = allActors.Count - 1; i >= 0; i--) { if (allActors[i].IsDead || Vector3.Distance(allActors[i].CurrentPosition, sourcePosition) > targetPositionDistance || lineSegment.DistToPoint(allActors[i].CurrentPosition) > allActors[i].Radius * 5f) { // If the actor is // 1) dead // 2) the distance from actor to source is greater than targetPos distance // 3) the distance to the actor is greater than the radious of all actors (?!?) // remove the actor from consideration allActors.RemoveAt(i); } } float sourcePositionsWithLineOfFireToTargetPositions = 0f; // num2 float losTargetPositionsCount = 0f; // num3 float weaponsWithUnobstructedLOF = 0f; // num4 collisionWorldPos = targetPosition; float shortestDistanceFromVectorToIteratedActor = 999999.9f; // num5 Weapon longestRangeWeapon = source.GetLongestRangeWeapon(false, false); float maximumWeaponRangeForSource = (longestRangeWeapon != null) ? longestRangeWeapon.MaxRange : 0f; // MY CHANGE: float adjustedSpotterRange = ___Combat.LOS.GetAdjustedSpotterRange(source, abstractActor); float adjustedSensorRange = ___Combat.LOS.GetAdjustedSensorRange(source, abstractActor); //LowVisibility.Logger.Log($"LineOfSight:GetLineOfFireUncached:pre - using sensorRange:{adjustedSensorRange} instead of spotterRange:{adjustedSpotterRange}. Max weapon range is:{maximumWeaponRangeForSource} "); maximumWeaponRangeForSource = Mathf.Max(maximumWeaponRangeForSource, adjustedSensorRange, adjustedSpotterRange); for (int j = 0; j < lossourcePositions.Length; j++) { // Iterate the source positions (presumably each weapon has different source locations) for (int k = 0; k < lostargetPositions.Length; k++) { // Iterate the target positions (presumably each build/mech has differnet locations) losTargetPositionsCount += 1f; float distanceFromSourceToTarget = Vector3.Distance(lossourcePositions[j], lostargetPositions[k]); if (distanceFromSourceToTarget <= maximumWeaponRangeForSource) { // Possible match, check for collisions lineSegment = new LineSegment(lossourcePositions[j], lostargetPositions[k]); bool canUseDirectAttack = false; Vector3 vector; if (targetedBuildingGuid == null) { // Not a building, so check for compatible actors for (int l = 0; l < allActors.Count; l++) { if (lineSegment.DistToPoint(allActors[l].CurrentPosition) < allActors[l].Radius) { vector = NvMath.NearestPointStrict(lossourcePositions[j], lostargetPositions[k], allActors[l].CurrentPosition); float distanceFromVectorToIteratedActor = Vector3.Distance(vector, allActors[l].CurrentPosition); if (distanceFromVectorToIteratedActor < allActors[l].HighestLOSPosition.y) { // TODO: Could I have this flipped, and .y is the highest y in the path? This is checking for indirect fire? // If the height of the attack is less than the HighestLOSPosition.y value, we have found the match? canUseDirectAttack = true; weaponsWithUnobstructedLOF += 1f; if (distanceFromVectorToIteratedActor < shortestDistanceFromVectorToIteratedActor) { shortestDistanceFromVectorToIteratedActor = distanceFromVectorToIteratedActor; collisionWorldPos = vector; } break; } } } } // If there is a source position with LOS to the target, record it if (__instance.HasLineOfFire(lossourcePositions[j], lostargetPositions[k], targetedBuildingGuid, maximumWeaponRangeForSource, out vector)) { sourcePositionsWithLineOfFireToTargetPositions += 1f; if (targetedBuildingGuid != null) { break; } } else { // There is no LineOfFire between the source and targert position if (canUseDirectAttack) { weaponsWithUnobstructedLOF -= 1f; } float distanceFromVectorToSourcePosition = Vector3.Distance(vector, sourcePosition); if (distanceFromVectorToSourcePosition < shortestDistanceFromVectorToIteratedActor) { shortestDistanceFromVectorToIteratedActor = distanceFromVectorToSourcePosition; // There is a collection somewhere in the path (MAYBE?) collisionWorldPos = vector; } } } } if (targetedBuildingGuid != null && sourcePositionsWithLineOfFireToTargetPositions > 0.5f) { break; } } // If a building, ignore the various positions (WHY?) float ratioSourcePosToTargetPos = (targetedBuildingGuid != null) ? sourcePositionsWithLineOfFireToTargetPositions : (sourcePositionsWithLineOfFireToTargetPositions / losTargetPositionsCount); // "MinRatioFromActors": 0.2, float b = ratioSourcePosToTargetPos - ___Combat.Constants.Visibility.MinRatioFromActors; float ratioDirectAttacksToTargetPositions = Mathf.Min(weaponsWithUnobstructedLOF / losTargetPositionsCount, b); if (ratioDirectAttacksToTargetPositions > 0.001f) { ratioSourcePosToTargetPos -= ratioDirectAttacksToTargetPositions; } //LowVisibility.Logger.Log($"LineOfSight:GetLineOfFireUncached:pre - ratio is:{ratioSourcePosToTargetPos} / direct:{ratioDirectAttacksToTargetPositions} / b:{b}"); // "RatioFullVis": 0.79, // "RatioObstructedVis": 0.41, if (ratioSourcePosToTargetPos >= ___Combat.Constants.Visibility.RatioFullVis) { __result = LineOfFireLevel.LOFClear; } else if (ratioSourcePosToTargetPos >= ___Combat.Constants.Visibility.RatioObstructedVis) { __result = LineOfFireLevel.LOFObstructed; } else { __result = LineOfFireLevel.LOFBlocked; } Mod.Log.Trace?.Write($"LOS:GLOFU LOS result is:{__result}"); return(false); }
static bool Prefix( ref Vector3 position, ref Quaternion rotation, ref bool isPositionLocked, ref AbstractActor selectedActor, ref ICombatant target, ref bool usingMultifire, ref bool isLocked, ref bool isMelee, WeaponRangeIndicators __instance) { CombatHUD HUD = (CombatHUD)ReflectionHelper.GetPrivateProperty(__instance, "HUD"); if (__instance.DEBUG_showLOSLines) { __instance.GetDebugDrawer().DrawLines(selectedActor, HUD.SelectionHandler.ActiveState, target); } LineRenderer line = (LineRenderer)ReflectionHelper.InvokePrivateMethode(__instance, "getLine", new object[] { }); Vector3 vector = Vector3.Lerp(position, position + selectedActor.HighestLOSPosition, __instance.sourceLaserDestRatio); Vector3 vector2 = Vector3.Lerp(target.CurrentPosition, target.TargetPosition, __instance.targetLaserDestRatio); AbstractActor abstractActor = target as AbstractActor; if (isMelee) { line.startWidth = __instance.LOSWidthBegin; line.endWidth = __instance.LOSWidthEnd; line.material = __instance.MaterialInRange; line.startColor = __instance.FinalLOSLockedTarget.color; line.endColor = __instance.FinalLOSLockedTarget.color; line.positionCount = 2; line.SetPosition(0, vector); Vector3 vector3 = vector - vector2; vector3.Normalize(); vector3 *= __instance.LineEndOffset; vector2 += vector3; line.SetPosition(1, vector2); ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, true }); List <AbstractActor> allActors = selectedActor.Combat.AllActors; allActors.Remove(selectedActor); allActors.Remove(abstractActor); PathNode pathNode; Vector3 attackPosition; float num; selectedActor.Pathing.GetMeleeDestination(abstractActor, allActors, out pathNode, out attackPosition, out num); HUD.InWorldMgr.ShowAttackDirection(HUD.SelectedActor, abstractActor, HUD.Combat.HitLocation.GetAttackDirection(attackPosition, target), vector2.y, MeleeAttackType.Punch, 0); } if (abstractActor != null) { HUD.InWorldMgr.SetGuardedActive(abstractActor); } FiringPreviewManager.PreviewInfo previewInfo = HUD.SelectionHandler.ActiveState.FiringPreview.GetPreviewInfo(target); AttackDirection direction = HUD.Combat.HitLocation.GetAttackDirection(position, target); bool status = false; Color chosenColor = __instance.FinalLOSInRange.color; if (direction == AttackDirection.FromFront && ModSettings.Direct.Active) { chosenColor = ModSettings.Direct.Color; status = true; } if ((direction == AttackDirection.FromLeft || direction == AttackDirection.FromRight) && ModSettings.Side.Active) { chosenColor = ModSettings.Side.Color; status = true; } if (direction == AttackDirection.FromBack && ModSettings.Back.Active) { chosenColor = ModSettings.Back.Color; status = true; } if ((target.UnitType == UnitType.Turret || target.UnitType == UnitType.Building) && status) { chosenColor = ModSettings.Direct.Color; } if (previewInfo.availability == FiringPreviewManager.TargetAvailability.NotSet) { Debug.LogError("Error - trying to draw line with no FiringPreviewManager availability!"); } bool flag = HUD.SelectionHandler.ActiveState.SelectionType != SelectionType.Sprint || HUD.SelectedActor.CanShootAfterSprinting; bool flag2 = !isPositionLocked && previewInfo.availability != FiringPreviewManager.TargetAvailability.BeyondMaxRange && previewInfo.availability != FiringPreviewManager.TargetAvailability.BeyondRotation; if (flag && (previewInfo.IsCurrentlyAvailable || flag2)) { if (usingMultifire) { if (target == HUD.SelectedTarget) { line.startColor = (line.endColor = __instance.FinalLOSMultiTargetKBSelection.color); } else if (isLocked) { line.startColor = (line.endColor = __instance.FinalLOSLockedTarget.color); } else { line.startColor = (line.endColor = __instance.FinalLOSUnlockedTarget.color); } } else { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); Color endColor = Color.Lerp(Color.clear, __instance.FinalLOSInRange.color, shotQuality); line.startColor = (line.endColor = endColor); } line.material = __instance.MaterialInRange; if (previewInfo.HasLOF) { line.positionCount = 2; line.SetPosition(0, vector); Vector3 vector4 = vector - vector2; vector4.Normalize(); vector4 *= __instance.LineEndOffset; vector2 += vector4; if (previewInfo.LOFLevel == LineOfFireLevel.LOFClear) { if (target == HUD.SelectionHandler.ActiveState.FacingEnemy) { if (status) { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); line.material.color = Color.white; line.endColor = line.startColor = Color.Lerp(Color.clear, chosenColor, shotQuality); } line.startWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; line.endWidth = __instance.LOSWidthEnd * __instance.LOSWidthFacingTargetMultiplier; } else { if (status) { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); line.material.color = Color.white; line.endColor = line.startColor = Color.Lerp(Color.clear, chosenColor, shotQuality); if (direction == AttackDirection.FromLeft || direction == AttackDirection.FromRight) { if (ModSettings.Side.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } line.startWidth = line.endWidth = ModSettings.Side.Thickness; } else if (direction == AttackDirection.FromBack) { if (ModSettings.Back.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } line.startWidth = line.endWidth = ModSettings.Back.Thickness; } else { if (ModSettings.Side.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } line.startWidth = line.endWidth = ModSettings.Direct.Thickness; } } } line.SetPosition(1, vector2); } else { if (target == HUD.SelectionHandler.ActiveState.FacingEnemy) { line.startWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; line.endWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; } else { line.startWidth = __instance.LOSWidthBegin; line.endWidth = __instance.LOSWidthBegin; } Vector3 vector5 = previewInfo.collisionPoint; vector5 = Vector3.Project(vector5 - vector, vector2 - vector) + vector; line.SetPosition(1, vector5); if (ModSettings.ObstructedAttackerSide.Active) { line.material.color = Color.white; line.startColor = line.endColor = ModSettings.ObstructedAttackerSide.Color; if (ModSettings.ObstructedAttackerSide.Colorside && direction != AttackDirection.ToProne) { line.startColor = line.endColor = chosenColor; } line.startWidth = line.endWidth = ModSettings.ObstructedAttackerSide.Thickness; if (ModSettings.ObstructedAttackerSide.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } } LineRenderer line2 = (LineRenderer)ReflectionHelper.InvokePrivateMethode(__instance, "getLine", new object[] { }); line2.positionCount = 2; line2.startWidth = __instance.LOSWidthBlocked; line2.endWidth = __instance.LOSWidthBlocked; line2.material = __instance.MaterialInRange; if (ModSettings.ObstructedTargetSide.Active) { line2.material.color = Color.white; line2.startColor = line2.endColor = ModSettings.ObstructedTargetSide.Color; line2.startWidth = line2.endWidth = ModSettings.ObstructedTargetSide.Thickness; if (ModSettings.ObstructedTargetSide.Dashed) { line2.material = __instance.MaterialOutOfRange; line2.material.color = line2.endColor; } } else { line2.startColor = line2.endColor = __instance.FinalLOSBlocked.color; line2.startWidth = line2.endWidth = __instance.LOSWidthBlocked; } line2.SetPosition(0, vector5); line2.SetPosition(1, vector2); GameObject coverIcon = (GameObject)ReflectionHelper.InvokePrivateMethode(__instance, "getCoverIcon", new object[] { }); if (!coverIcon.activeSelf) { coverIcon.SetActive(true); } coverIcon.transform.position = vector5; } } else { if (ModSettings.Indirect.Active) { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); Color couleur = ModSettings.Indirect.Color; if (ModSettings.Indirect.Colorside) { couleur = chosenColor; } Color color6 = Color.Lerp(Color.clear, couleur, shotQuality); if (ModSettings.Indirect.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = color6; line.startWidth = line.endWidth = ModSettings.Indirect.Thickness; } else { line.material.color = Color.white; line.endColor = line.startColor = color6; } } int num2 = Mathf.Min(Mathf.Max((int)(NvMath.SqrMagnitudeXZ(vector, vector2) / (__instance.IndirectFireSegFreq * __instance.IndirectFireSegFreq)), __instance.IndirectFireMinPoints), __instance.IndirectFireMaxPoints); Vector3[] pointsForArcDodgeBuildings = WeaponRangeIndicators.GetPointsForArcDodgeBuildings(num2, __instance.IndirectFireMinArcHeight, vector, vector2, HUD.Combat.MapMetaData, __instance.IndirectFireBuffer, __instance.IndirectFireMaxArcHeight, __instance.IndirectFireCheckFreq, false); line.positionCount = num2; line.SetPositions(pointsForArcDodgeBuildings); } ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, true }); if (abstractActor != null) { HUD.InWorldMgr.ShowAttackDirection(HUD.SelectedActor, abstractActor, HUD.Combat.HitLocation.GetAttackDirection(position, target), vector2.y, MeleeAttackType.NotSet, HUD.InWorldMgr.NumWeaponsTargeting(target)); } } else { line.positionCount = 2; line.SetPosition(0, vector); line.SetPosition(1, vector2); line.startColor = (line.endColor = __instance.FinalLOSOutOfRange.color); line.material = __instance.MaterialOutOfRange; ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, false }); } return(false); }
/*static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) * { * var targetPropertyGetter = AccessTools.Property(typeof(Weapon), "IndirectFireCapable").GetGetMethod(); * var replacementMethod = AccessTools.Method(typeof(ToHit_GetAllModifiersDescription), nameof(IndirectFireCapable)); * return Transpilers.MethodReplacer(instructions, targetPropertyGetter, replacementMethod); * } * * private static bool IndirectFireCapable(Weapon weapon) * { * //CustomAmmoCategoriesLog.Log.LogWrite("get ToHit_GetAllModifiersDescription IndirectFireCapable\n"); * return CustomAmmoCategories.getIndirectFireCapable(weapon); * }*/ public static bool Prefix(ToHit __instance, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot, ref string __result) { string str = string.Empty; bool flag = lofLevel < LineOfFireLevel.LOFObstructed && (CustomAmmoCategories.getIndirectFireCapable(weapon)); float rangeModifier = __instance.GetRangeModifier(weapon, attackPosition, targetPosition); float coverModifier = __instance.GetCoverModifier(attacker, target, lofLevel); float selfSpeedModifier = __instance.GetSelfSpeedModifier(attacker); float sprintedModifier = __instance.GetSelfSprintedModifier(attacker); float armMountedModifier = __instance.GetSelfArmMountedModifier(weapon); float stoodUpModifier = __instance.GetStoodUpModifier(attacker); float heightModifier = __instance.GetHeightModifier(attackPosition.y, targetPosition.y); float heatModifier = __instance.GetHeatModifier(attacker); float targetTerrainModifier = __instance.GetTargetTerrainModifier(target, targetPosition, false); float selfTerrainModifier = __instance.GetSelfTerrainModifier(attackPosition, false); float targetSpeedModifier = __instance.GetTargetSpeedModifier(target, weapon); float selfDamageModifier = __instance.GetSelfDamageModifier(attacker, weapon); float targetSizeModifier = __instance.GetTargetSizeModifier(target); float shutdownModifier = __instance.GetTargetShutdownModifier(target, false); float targetProneModifier = __instance.GetTargetProneModifier(target, false); float accuracyModifier1 = __instance.GetWeaponAccuracyModifier(attacker, weapon); float accuracyModifier2 = __instance.GetAttackerAccuracyModifier(attacker); float enemyEffectModifier = __instance.GetEnemyEffectModifier(target); float refireModifier = __instance.GetRefireModifier(weapon); float directFireModifier = __instance.GetTargetDirectFireModifier(target, flag); float indirectModifier = __instance.GetIndirectModifier(attacker, flag); float moraleAttackModifier = __instance.GetMoraleAttackModifier(target, isCalledShot); float weaponDirectFireModifier = CustomAmmoCategories.getDirectFireModifier(weapon); if (!NvMath.FloatIsNearZero(rangeModifier)) { str = string.Format("{0}RANGE {1:+#;-#}; ", (object)str, (object)(int)rangeModifier); } if (!NvMath.FloatIsNearZero(coverModifier)) { str = string.Format("{0}COVER {1:+#;-#}; ", (object)str, (object)(int)rangeModifier); } if (!NvMath.FloatIsNearZero(selfSpeedModifier)) { str = string.Format("{0}SELF-MOVED {1:+#;-#}; ", (object)str, (object)(int)selfSpeedModifier); } if (!NvMath.FloatIsNearZero(sprintedModifier)) { str = string.Format("{0}SELF-SPRINTED {1:+#;-#}; ", (object)str, (object)(int)sprintedModifier); } if (!NvMath.FloatIsNearZero(armMountedModifier)) { str = string.Format("{0}SELF-ARM MOUNTED {1:+#;-#}; ", (object)str, (object)(int)armMountedModifier); } if (!NvMath.FloatIsNearZero(stoodUpModifier)) { str = string.Format("{0}STOOD UP {1:+#;-#}; ", (object)str, (object)(int)stoodUpModifier); } if (!NvMath.FloatIsNearZero(heightModifier)) { str = string.Format("{0}HEIGHT {1:+#;-#}; ", (object)str, (object)(int)heightModifier); } if (!NvMath.FloatIsNearZero(heatModifier)) { str = string.Format("{0}HEAT {1:+#;-#}; ", (object)str, (object)(int)heatModifier); } if (!NvMath.FloatIsNearZero(targetTerrainModifier)) { str = string.Format("{0}TERRAIN {1:+#;-#}; ", (object)str, (object)(int)targetTerrainModifier); } if (!NvMath.FloatIsNearZero(selfTerrainModifier)) { str = string.Format("{0}TERRAIN SELF {1:+#;-#}; ", (object)str, (object)(int)selfTerrainModifier); } if (!NvMath.FloatIsNearZero(targetSpeedModifier)) { str = string.Format("{0}TARGET-SPEED {1:+#;-#}; ", (object)str, (object)(int)targetSpeedModifier); } if (!NvMath.FloatIsNearZero(selfDamageModifier)) { str = string.Format("{0}SELF-DAMAGE {1:+#;-#}; ", (object)str, (object)(int)selfDamageModifier); } if (!NvMath.FloatIsNearZero(targetSizeModifier)) { str = string.Format("{0}TARGET-SIZE {1:+#;-#}; ", (object)str, (object)(int)targetSizeModifier); } if (!NvMath.FloatIsNearZero(shutdownModifier)) { str = string.Format("{0}TARGET-SHUTDOWN {1:+#;-#}; ", (object)str, (object)(int)shutdownModifier); } if (!NvMath.FloatIsNearZero(targetProneModifier)) { str = string.Format("{0}TARGET-PRONE {1:+#;-#}; ", (object)str, (object)(int)targetProneModifier); } if (!NvMath.FloatIsNearZero(accuracyModifier1)) { str = string.Format("{0}ATTACKER-EFFECTS {1:+#;-#}; ", (object)str, (object)(int)accuracyModifier1); } if (!NvMath.FloatIsNearZero(accuracyModifier2)) { str = string.Format("{0}ATTACKER-SELF-EFFECTS {1:+#;-#}; ", (object)str, (object)(int)accuracyModifier2); } if (!NvMath.FloatIsNearZero(enemyEffectModifier)) { str = string.Format("{0}ENEMY-EFFECTS {1:+#;-#}; ", (object)str, (object)(int)enemyEffectModifier); } if (!NvMath.FloatIsNearZero(refireModifier)) { str = string.Format("{0}REFIRE {1:+#;-#}; ", (object)str, (object)(int)refireModifier); } if (!NvMath.FloatIsNearZero(directFireModifier)) { str = string.Format("{0}DIRECT-FIRE {1:+#;-#}; ", (object)str, (object)(int)directFireModifier); } if (!NvMath.FloatIsNearZero(indirectModifier)) { str = string.Format("{0}INDIRECT-FIRE {1:+#;-#}; ", (object)str, (object)(int)indirectModifier); } if (!NvMath.FloatIsNearZero(moraleAttackModifier)) { str = string.Format("{0}CALLED-SHOT {1:+#;-#}; ", (object)str, (object)(int)moraleAttackModifier); } float b = rangeModifier + coverModifier + selfSpeedModifier + sprintedModifier + armMountedModifier + stoodUpModifier + heightModifier + heatModifier + targetTerrainModifier + selfTerrainModifier + targetSpeedModifier + selfDamageModifier + targetSizeModifier + shutdownModifier + targetProneModifier + accuracyModifier1 + accuracyModifier2 + enemyEffectModifier + refireModifier + directFireModifier + indirectModifier + moraleAttackModifier; if (flag == false) { CustomAmmoCategoriesLog.Log.LogWrite(attacker.DisplayName + " has LOS on " + target.DisplayName + ". Apply DirectFireModifier " + weaponDirectFireModifier + "\n"); if (!NvMath.FloatIsNearZero(weaponDirectFireModifier)) { str = string.Format("{0}WEAPON-DIRECT-FIRE {1:+#;-#}; ", (object)str, (object)(int)weaponDirectFireModifier); } b += weaponDirectFireModifier; } CombatGameState combat = (CombatGameState)typeof(ToHit).GetField("combat", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); if ((double)b < 0.0 && !combat.Constants.ResolutionConstants.AllowTotalNegativeModifier) { b = 0.0f; } float allModifiers = __instance.GetAllModifiers(attacker, weapon, target, attackPosition, targetPosition, lofLevel, isCalledShot); if (!NvMath.FloatsAreEqual(allModifiers, b)) { CustomAmmoCategoriesLog.Log.LogWrite("Strange behavior calced modifier " + b + " not equal geted " + allModifiers + "\n"); AttackDirector.attackLogger.LogError((object)("ERROR!!! breakdown of Universal Modifier didn't match actual Universal Modifier. Check TargetingRules! current modifier: " + (object)b + ", doubleCheck modifier: " + (object)allModifiers)); } __result = str; return(false); }
/// <summary> /// The compress 4x4 block. /// </summary> /// <param name="block"> /// The block of 4x4 colors. /// </param> /// <param name="mask"> /// The mask of 4x4 pixels (1 - visible, 0 - not visible). /// </param> /// <param name="compressColors"> /// Four compressed colors. /// </param> /// <param name="c0"> /// The color0. /// </param> /// <param name="c1"> /// The color1. /// </param> /// <param name="texels"> /// Texels. /// </param> /// <returns> /// The approximation error<see cref="double"/>. /// </returns> public static double CompressBlock(Color[] block, int[] mask, out Color[] compressColors, out ushort c0, out ushort c1, out uint texels) { #region Init bool hasAlpha = false; double bestError = 0; Vector3[] inputPoints = new Vector3[block.Length]; bool[] uniqueFlags = new bool[block.Length]; int[] lowIds = new int[block.Length]; int[] highIds = new int[block.Length]; int count = 0; int countWithmask = 0; double maxDistance = -1; double maxDistanceWithMask = -1; for (int i = 0; i < block.Length; i++) { inputPoints[i] = ColorToVector(block[i]); if (block[i].A >= 8) { bool dubled = false; bool dubledWithMask = false; for (int j = i - 1; j >= 0 && (!dubled || !dubledWithMask); --j) { if (block[j].A >= 8) { double dist = (inputPoints[i] - inputPoints[j]).LengthSquared(); if (uniqueFlags[j]) { dubled |= dist < 1e-6; if (dist > maxDistance) { maxDistance = dist; lowIds[0] = j; highIds[0] = i; } } if (mask[j] > 0 && mask[i] > 0) { dubledWithMask |= dist < 1e-6; if (dist > maxDistanceWithMask) { maxDistanceWithMask = dist; lowIds[2] = j; highIds[2] = i; } } } } if (!dubled) { count++; uniqueFlags[i] = true; if (maxDistance < 0) { lowIds[0] = i; } } if (!dubledWithMask && mask[i] > 0) { countWithmask++; if (maxDistanceWithMask < 0) { lowIds[2] = i; } } } else { hasAlpha = true; } } #endregion #region Compress bool compressed = false; bool hasAlpha0 = hasAlpha; Color[] dxtBoundColors = null; if (count <= 4) { compressed = IsCompressedBlock(block, uniqueFlags, count, lowIds[0], highIds[0], out dxtBoundColors, ref hasAlpha); } Vector3[] dxtBoundPoints = new Vector3[2]; if (!compressed) { hasAlpha = hasAlpha0; if (countWithmask == 0) { bestError = 0; dxtBoundPoints[0] = inputPoints[lowIds[0]]; dxtBoundPoints[1] = inputPoints[highIds[0]]; hasAlpha = true; } else if (countWithmask == 1) { bestError = Math.Max(0, maxDistance); uint dist0 = ColorSquaredDistance(block[lowIds[2]], block[lowIds[0]]); uint dist1 = ColorSquaredDistance(block[lowIds[2]], block[highIds[0]]); if (dist0 > dist1) { dxtBoundPoints[1] = inputPoints[lowIds[0]]; } else { dxtBoundPoints[1] = inputPoints[highIds[0]]; } dxtBoundPoints[0] = inputPoints[lowIds[2]]; hasAlpha = true; } else { Vector3 maxColor = inputPoints[lowIds[2]]; Vector3 minColor = inputPoints[highIds[2]]; UInt16 color0 = RoundAndExpand(ref maxColor); UInt16 color1 = RoundAndExpand(ref minColor); hasAlpha |= color0 == color1; if (color0 < color1) { NvMath.Swap(ref maxColor, ref minColor); NvMath.Swap(ref color0, ref color1); } dxtBoundPoints[0] = maxColor; dxtBoundPoints[1] = minColor; if (!hasAlpha) { uint indices = ComputeIndices4(inputPoints, maxColor, minColor); OptimizeEndPoints4(inputPoints, ref dxtBoundPoints, ref indices); } //else //{ // uint indices = computeIndices3(inputPoints, maxColor, minColor); // optimizeEndPoints3(inputPoints, ref dxtBoundPoints, ref indices); //} } } else { for (int i = 0; i < 2; i++) { dxtBoundPoints[i] = ColorToVector(dxtBoundColors[i]); } } #endregion #region Finilize c0 = RoundAndExpand(ref dxtBoundPoints[0]); c1 = RoundAndExpand(ref dxtBoundPoints[1]); if (c0 == c1) { hasAlpha = true; } if (c0 > c1 == hasAlpha) { NvMath.Swap(ref c0, ref c1); NvMath.Swap(ref dxtBoundPoints[0], ref dxtBoundPoints[1]); } if (c0 > c1) { NvMath.Swap(ref dxtBoundPoints[0], ref dxtBoundPoints[1]); } compressColors = new Color[4]; for (int i = 0; i < 2; i++) { compressColors[i] = VectorToColor(dxtBoundPoints[i]); } if (hasAlpha) { compressColors[2] = SumColors(compressColors[0], compressColors[1], 1, 1); compressColors[3] = Color.FromArgb(0, 0, 0, 0); } else { compressColors[2] = SumColors(compressColors[0], compressColors[1], 5, 3); compressColors[3] = SumColors(compressColors[0], compressColors[1], 3, 5); } bestError = 0; texels = 0; for (int i = 0; i < 16; i++) { byte ci; if (block[i].A >= 8) { double dist0 = ColorSquaredDistance(block[i], compressColors[0]); double dist1 = ColorSquaredDistance(block[i], compressColors[1]); double dist2 = ColorSquaredDistance(block[i], compressColors[2]); double dist3 = ColorSquaredDistance(block[i], compressColors[3]); if (dist0 < dist2) { ci = 0; bestError += dist0; } else if (dist1 < dist2 && dist1 < dist3) { ci = 1; bestError += dist1; } else if (dist2 < dist3) { ci = 2; bestError += dist2; } else { ci = 3; bestError += dist3; } } else { ci = 3; } texels |= (uint)(ci << (2 * i)); } #endregion return(Math.Sqrt(bestError / 16)); }