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);
        }
示例#5
0
        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);
        }
示例#6
0
        /*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));
        }