Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        public static Vector3 GetBuildingHitPosition(this LineOfSight LOS, AbstractActor attacker, BattleTech.Building target, Vector3 attackPosition, float weaponRange, Vector3 origHitPosition)
        {
            Vector3 a                 = origHitPosition;
            Vector3 vector3_1         = attackPosition + attacker.HighestLOSPosition;
            string  guid              = target.GUID;
            Vector3 collisionWorldPos = Vector3.zero;
            bool    flag              = false;

            if ((UnityEngine.Object)target.BuildingRep == (UnityEngine.Object)null)
            {
                return(a);
            }
            foreach (Collider allRaycastCollider in target.GameRep.AllRaycastColliders)
            {
                if (LOS.HasLineOfFire(vector3_1, allRaycastCollider.bounds.center, guid, weaponRange, out collisionWorldPos))
                {
                    a    = allRaycastCollider.bounds.center;
                    flag = true;
                    break;
                }
            }
            for (int index1 = 0; index1 < target.LOSTargetPositions.Length; ++index1)
            {
                if (LOS.HasLineOfFire(vector3_1, target.LOSTargetPositions[index1], guid, weaponRange, out collisionWorldPos))
                {
                    if (flag)
                    {
                        Vector3 end = Vector3.Lerp(a, target.LOSTargetPositions[index1], UnityEngine.Random.Range(0.0f, 0.15f));
                        if (LOS.HasLineOfFire(vector3_1, end, guid, weaponRange, out collisionWorldPos))
                        {
                            a = end;
                        }
                    }
                    else
                    {
                        Vector3 vector3_2 = a;
                        for (int index2 = 0; index2 < 10; ++index2)
                        {
                            vector3_2 = Vector3.Lerp(vector3_2, target.LOSTargetPositions[index1], UnityEngine.Random.Range(0.1f, 0.6f));
                            if (LOS.HasLineOfFire(vector3_1, vector3_2, guid, weaponRange, out collisionWorldPos))
                            {
                                a    = vector3_2;
                                flag = true;
                                break;
                            }
                        }
                        if (!flag)
                        {
                            a    = target.LOSTargetPositions[index1];
                            flag = true;
                        }
                    }
                }
            }
            Ray ray = new Ray(vector3_1, a - vector3_1);

            foreach (Collider allRaycastCollider in target.GameRep.AllRaycastColliders)
            {
                GameObject gameObject = allRaycastCollider.gameObject;
                bool       activeSelf = gameObject.activeSelf;
                gameObject.SetActive(true);
                RaycastHit hitInfo;
                if (allRaycastCollider.Raycast(ray, out hitInfo, 1000f))
                {
                    gameObject.SetActive(activeSelf);
                    return(hitInfo.point);
                }
                gameObject.SetActive(activeSelf);
            }
            return(a);
        }