コード例 #1
0
    public static float RotationTo(this LocAndOffsets from, LocAndOffsets to)
    {
        var fromLoc = from.ToInches2D();
        var toLoc   = to.ToInches2D();

        return((toLoc - fromLoc).GetWorldRotation());
    }
コード例 #2
0
    private void PartySelectedFormationMoveToPosition_FindPath(GameObject partyMember, int count,
                                                               LocAndOffsets from, LocAndOffsets plannedPos, out LocAndOffsets actualPos)
    {
        actualPos = plannedPos;

        if (IsBlocked(plannedPos.ToInches2D(), partyMember.GetRadius()))
        {
            var pq = new PathQuery();
            pq.flags2  = (int)AnimPathDataFlags.UNK_2000;
            pq.flags   = PathQueryFlags.PQF_FORCED_STRAIGHT_LINE | PathQueryFlags.PQF_HAS_CRITTER;
            pq.critter = partyMember;
            pq.from    = from;
            pq.to      = plannedPos;
            pq.flags   = PathQueryFlags.PQF_FORCED_STRAIGHT_LINE | PathQueryFlags.PQF_HAS_CRITTER |
                         PathQueryFlags.PQF_TO_EXACT | PathQueryFlags.PQF_800;
            pq.distanceToTargetMin = count * locXY.INCH_PER_TILE;
            if (!GameSystems.Combat.IsCombatActive())
            {
                pq.flags |= PathQueryFlags.PQF_IGNORE_CRITTERS;
            }

            if (GameSystems.PathX.FindPath(pq, out var pathResult))
            {
                actualPos = pathResult.nodes[pathResult.nodeCount - 1];
            }
        }
    }
コード例 #3
0
    private bool FindFreeTargetPos(ref LocAndOffsets loc, float radius)
    {
        var loc2d = loc.ToInches2D();

        if (!IsBlocked(loc2d, radius))
        {
            return(true);
        }

        var i = 0;

        for (var j = -1; j > -18; j--)
        {
            int k;
            var yOffset = i * locXY.INCH_PER_SUBTILE;
            var altPos  = loc2d;
            for (k = j; k < i; k++)
            {
                var xOffset = k * locXY.INCH_PER_SUBTILE;

                altPos = loc2d + new Vector2(xOffset, -yOffset);
                if (!IsBlocked(altPos, radius))
                {
                    break;
                }

                altPos = loc2d + new Vector2(-xOffset, yOffset);
                if (!IsBlocked(altPos, radius))
                {
                    break;
                }

                altPos = loc2d + new Vector2(-xOffset, -yOffset);
                if (!IsBlocked(altPos, radius))
                {
                    break;
                }

                altPos = loc2d + new Vector2(xOffset, yOffset);
                if (!IsBlocked(altPos, radius))
                {
                    break;
                }
            }

            if (k != i)
            {
                loc = LocAndOffsets.FromInches(altPos);
                return(true);
            }

            i++;
        }

        return(i != 0);
    }
コード例 #4
0
    public bool SetConeTargets(LocAndOffsets targetLocation)
    {
        result.flags    = PickerResultFlags.PRF_HAS_LOCATION | PickerResultFlags.PRF_HAS_MULTI_OBJ;
        result.location = targetLocation;
        result.offsetz  = 0;
        result.handle   = null;

        var originPos  = caster.GetLocationFull();
        var coneOrigin = originPos.ToInches2D();
        var coneTarget = targetLocation.ToInches2D();

        float radiusInches;

        if (!flagsTarget.HasFlag(UiPickerFlagsTarget.FixedRadius))
        {
            radiusInches = (coneTarget - coneOrigin).Length();
        }
        else
        {
            radiusInches = radiusTarget * locXY.INCH_PER_FEET;
        }

        var arcRad   = Angles.ToRadians(degreesTarget);
        var arcStart = (coneTarget - coneOrigin).GetWorldRotation() - arcRad;

        using var objList = ObjList.ListCone(originPos, radiusInches, arcStart, arcRad, ObjectListFilter.OLC_ALL);
        result.objList    = new List <GameObject>(objList);

        if (!flagsTarget.HasFlag(UiPickerFlagsTarget.Unknown80h))
        {
            RemoveTargetsNotInLineOfSightOf(originPos);
        }

        DoExclusions();

        return(true);
    }
コード例 #5
0
    public void TestRaycast()
    {
        var origin = new LocAndOffsets(new locXY(496, 458), -9.42809f, -8.42809f);
        var target = new LocAndOffsets(new locXY(512, 611), -7.42809f, -7.42809f);
        var radius = 17.5f;

        var ray_search = new RaycastPointSearchPacket();

        ray_search.origin = origin.ToInches2D();
        ray_search.target = target.ToInches2D();
        ray_search.radius = radius;

        ray_search.direction  = ray_search.target - ray_search.origin;
        ray_search.rangeInch  = ray_search.direction.Length();
        ray_search.direction /= ray_search.rangeInch;

        ray_search.absOdotU = Vector2.Dot(ray_search.direction, ray_search.origin);

        var locBeforeCover = target;
        SearchPointAlongRay search_func = RaycastPacket.IsPointCloseToSegment;

        var tileRadius = 1 + (int)(radius / locXY.INCH_PER_TILE);

        TestContext.Out.WriteLine(tileRadius.ToString());
        var tile_rect = RaycastPacket.BuildSearchRectangle(ray_search.origin, ray_search.target);

        var canFly = false;

        foreach (var s in tile_rect)
        {
            //int left = Math.Max(0, s.TileRectangle.Left - tileRadius);
            //int top = Math.Max(0, s.TileRectangle.Top - tileRadius);
            //int right = Math.Min(64, s.TileRectangle.Right + tileRadius);
            //int bottom = Math.Min(64, s.TileRectangle.Bottom + tileRadius);

            int left   = s.TileRectangle.Left;
            int top    = s.TileRectangle.Top;
            int right  = s.TileRectangle.Right;
            int bottom = s.TileRectangle.Bottom;

            TestContext.Out.WriteLine($"{s.SectorLoc.X} {s.SectorLoc.Y} {left},{top} {right},{bottom}");
        }
        TestContext.Out.WriteLine("OLD OLD OLD");

        if (!PreciseSectorRows.Build(tile_rect, out var sector_tiles))
        {
            return;
        }

        var local_254 = Math.Min(origin.location.locx, target.location.locx);
        var local_25c = Math.Max(origin.location.locx, target.location.locx);
        var local_2a4 = Math.Min(origin.location.locy, target.location.locy);
        var local_2b4 = Math.Max(origin.location.locy, target.location.locy);

/*
 *          local_254 -= tileRadius;
 *          local_2a4 -= tileRadius;
 *          local_25c += tileRadius;
 *          local_2b4 += tileRadius;
 */
        for (var local_2dc = 0; local_2dc < sector_tiles.RowCount; local_2dc++)
        {
            ref var pPVar2 = ref sector_tiles.Rows[local_2dc];

            Span <int> local_208 = stackalloc int[pPVar2.colCount];
            Span <int> local_1d8 = stackalloc int[pPVar2.colCount];

            for (var i = 0; i < pPVar2.colCount; i++)
            {
                local_208[i] = pPVar2.startTiles[i];
                local_1d8[i] = 64 - pPVar2.strides[i];
            }

            for (var local_2f0 = 0; local_2f0 < pPVar2.colCount; local_2f0++)
            {
                var sectorBaseTile = pPVar2.sectors[local_2f0].GetBaseTile();
                var sectorTileMinX = local_254 - sectorBaseTile.locx;
                var sectorTileMaxX = local_25c - sectorBaseTile.locx;
                var sectorTileMinY = local_2a4 - sectorBaseTile.locy;
                var sectorTileMaxY = local_2b4 - sectorBaseTile.locy;
                if (sectorTileMinX < 0)
                {
                    sectorTileMinX = 0;
                }

                if (sectorTileMinY < 0)
                {
                    sectorTileMinY = 0;
                }

                if (sectorTileMaxX > 63)
                {
                    sectorTileMaxX = 63;
                }

                if (sectorTileMaxY > 63)
                {
                    sectorTileMaxY = 63;
                }

                TestContext.Out.WriteLine($"{pPVar2.sectors[local_2f0].X} {pPVar2.sectors[local_2f0].Y} {sectorTileMinX},{sectorTileMinY}->{sectorTileMaxX},{sectorTileMaxY}");
            }
        }
コード例 #6
0
    public List <Light3d> FindLights(LocAndOffsets atLocation, float radius)
    {
        List <Light3d> lights = new List <Light3d>();

        if (GameSystems.Light.IsGlobalLightEnabled)
        {
            Light3d light       = new Light3d();
            var     legacyLight = GameSystems.Light.GlobalLight;
            light.type  = (Light3dType)legacyLight.type;
            light.color = legacyLight.Color;
            light.dir.X = legacyLight.dir.X;
            light.dir.Y = legacyLight.dir.Y;
            light.dir.Z = legacyLight.dir.Z;
            light.pos.X = legacyLight.pos.X;
            light.pos.Y = legacyLight.pos.Y;
            light.pos.Z = legacyLight.pos.Z;
            light.range = legacyLight.range;
            light.phi   = legacyLight.phi;
            lights.Add(light);
        }

        if (radius == 0)
        {
            return(lights);
        }

        // Build a box that has twice the radius convert to tiles as it's width/height
        // For some reason, ToEE will add one more INCH_PER_TILE here, which translates to
        // roughly 28 tiles more search radius than is needed
        var boxDimensions = (int)(radius / locXY.INCH_PER_TILE + locXY.INCH_PER_TILE);
        var tileX1        = atLocation.location.locx - 1 - boxDimensions;
        var tileX2        = atLocation.location.locx + 1 + boxDimensions;
        var tileY1        = atLocation.location.locy - 1 - boxDimensions;
        var tileY2        = atLocation.location.locy + 1 + boxDimensions;

        using var sectorIterator = new SectorIterator(tileX1, tileX2, tileY1, tileY2);

        var atPos = atLocation.ToInches2D();

        while (sectorIterator.HasNext)
        {
            using var sector = sectorIterator.Next();

            foreach (ref var light in sector.Lights)
            {
                int         type;
                LinearColor color;
                Vector3     direction;
                float       range, phi;
                var         lightPos = light.position.ToInches2D();

                if ((light.flags & 0x40) != 0)
                {
                    if (GameSystems.Light.IsNight)
                    {
                        type      = light.light2.type;
                        color     = light.light2.color;
                        direction = light.light2.direction;
                        range     = light.range; // Notice how it's using light 1's range
                        phi       = light.light2.phi;

                        /*
                         * Kill the daytime particle system if it's night and the
                         * daytime particle system is still alive.
                         */
                        if (light.partSys.handle != null)
                        {
                            GameSystems.ParticleSys.Remove(light.partSys.handle);
                            light.partSys.handle = null;
                        }

                        /*
                         * If the nighttime particle system has not yet been started,
                         * do it here.
                         */
                        ref var nightPartSys = ref light.light2.partSys;
                        if (nightPartSys.handle == null && nightPartSys.hashCode != 0)
                        {
                            var centerOfTile = light.position.ToInches3D(light.offsetZ);
                            nightPartSys.handle = GameSystems.ParticleSys.CreateAt(
                                nightPartSys.hashCode, centerOfTile
                                );
                        }
                    }
                    else
                    {
                        type      = light.type;
                        color     = light.color;
                        direction = light.direction;
                        range     = light.range;
                        phi       = light.phi;

                        // This is just the inverse of what we're doing at night (see above)
                        ref var nightPartSys = ref light.light2.partSys;
                        if (nightPartSys.handle != null)
                        {
                            GameSystems.ParticleSys.Remove(nightPartSys.handle);
                            nightPartSys.handle = null;
                        }

                        ref var dayPartSys = ref light.partSys;
                        if (dayPartSys.handle == null && dayPartSys.hashCode != 0)
                        {
                            var centerOfTile = light.position.ToInches3D(light.offsetZ);
                            dayPartSys.handle = GameSystems.ParticleSys.CreateAt(
                                dayPartSys.hashCode, centerOfTile
                                );
                        }
                    }
                }
コード例 #7
0
    public int PartySelectedFormationMoveToPosition(LocAndOffsets loc, bool mayWalk)
    {
        var selectedMembers = GameSystems.Party.Selected;

        if (selectedMembers.Count == 0)
        {
            return(1);
        }

        var maxRadius = float.MinValue;

        foreach (var selectedMember in selectedMembers)
        {
            if (!GameSystems.Critter.IsDeadNullDestroyed(selectedMember))
            {
                maxRadius = Math.Max(maxRadius, selectedMember.GetRadius());
            }
        }

        Span <LocAndOffsets> plannedPositions = stackalloc LocAndOffsets[selectedMembers.Count];

        if (!FindFreeTargetPos(ref loc, maxRadius))
        {
            return(1);
        }

        // NOTE: There seems to have been a bug in Vanilla where it wanted to
        // find the average center of the party, but never actually updated the obj
        // it took the position of. So it ended up just taking the leader's position.
        var leaderPos = selectedMembers[0].GetLocationFull().ToInches2D();
        var targetPos = loc.ToInches2D();

        // This rotation is used to rotate the formation at the target point
        var formationRotation = MathF.PI - MathF.Atan2(targetPos.X - leaderPos.X, targetPos.Y - leaderPos.Y);

        if (!GameSystems.Critter.IsDeadNullDestroyed(selectedMembers[0]))
        {
            plannedPositions[0] = loc;
        }

        for (var selectedIdx = 0; selectedIdx < selectedMembers.Count; selectedIdx++)
        {
            var obj = selectedMembers[selectedIdx];
            if (GameSystems.Critter.IsDeadNullDestroyed(obj))
            {
                continue;
            }

            var partyMemberRadius = obj.GetRadius();

            GetFormationOffset(obj, formationRotation, out var formationOffX, out var formationOffY);
            if (selectedMembers.Count < 2)
            {
                plannedPositions[selectedIdx] = loc;
            }
            else
            {
                var formationOffLen = MathF.Sqrt(formationOffY * formationOffY + formationOffX * formationOffX);
                // Remember that the length of the formation offset can be 0 in case it's dead-center
                if (formationOffLen > locXY.INCH_PER_SUBTILE)
                {
                    // Normalize the formation offset
                    var formationOffNormX = formationOffX / formationOffLen;
                    var formationOffNormY = formationOffY / formationOffLen;
                    var formationOffDir   = new Vector2(formationOffNormX, formationOffNormY);

                    var local_90 = 0.0f;
                    for (; local_90 < formationOffLen; local_90 += locXY.INCH_PER_SUBTILE)
                    {
                        var formationShift = local_90 * formationOffDir;
                        var formationPos   = targetPos + formationShift;

                        if (!IsBlocked(formationPos, maxRadius))
                        {
                            plannedPositions[selectedIdx] = LocAndOffsets.FromInches(formationPos);
                            break;
                        }
                    }

                    if (local_90 >= locXY.INCH_PER_SUBTILE)
                    {
                        // It somehow falls back to the previous location even if unblocked ???
                        var formationPos = targetPos + (local_90 - locXY.INCH_PER_SUBTILE) * formationOffDir;
                        plannedPositions[selectedIdx] = LocAndOffsets.FromInches(formationPos);
                    }
                }
                else
                {
                    plannedPositions[selectedIdx] = loc;
                }
            }

            var previousPositions = plannedPositions.Slice(0, selectedIdx);

            // We have to do conflict resolution if another party member before this one
            // chose a colliding position
            if (FindIntersectingPosition(selectedMembers, previousPositions,
                                         plannedPositions[selectedIdx].ToInches2D(), partyMemberRadius))
            {
                int upperBound;
                for (upperBound = 1; upperBound < 18; upperBound++)
                {
                    var local_84 = upperBound * locXY.INCH_PER_SUBTILE;

                    int local_8c;
                    var alternatePos = plannedPositions[selectedIdx].ToInches2D();
                    for (local_8c = -upperBound; local_8c < upperBound; local_8c++)
                    {
                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X += local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y -= local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }

                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X -= local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y += local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }

                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X -= local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y -= local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }

                        alternatePos    = plannedPositions[selectedIdx].ToInches2D();
                        alternatePos.X += local_8c * locXY.INCH_PER_SUBTILE;
                        alternatePos.Y += local_84;
                        if (!FindIntersectingPosition(selectedMembers, previousPositions, alternatePos,
                                                      partyMemberRadius) &&
                            !IsBlocked(alternatePos, partyMemberRadius))
                        {
                            break;
                        }
                    }

                    if (local_8c != upperBound)
                    {
                        plannedPositions[selectedIdx] = LocAndOffsets.FromInches(alternatePos);
                        break;
                    }
                }

                if (upperBound == 18)
                {
                    Logger.Info("Unable to find suitable formation position after 18 iterations.");
                }
            }
        }

        for (var i = 0; i < selectedMembers.Count; i++)
        {
            var obj = selectedMembers[i];
            if (!GameSystems.Critter.IsDeadNullDestroyed(obj))
            {
                PartySelectedFormationMoveToPosition_FindPath(obj, selectedMembers.Count, loc,
                                                              plannedPositions[i], out var actualTargetPos);
                if (!mayWalk)
                {
                    GameSystems.Anim.PushRunToTile(obj, actualTargetPos);
                    GameSystems.Anim.TurnOnRunning();
                }
                else
                {
                    GameSystems.Anim.PushMoveToTile(obj, actualTargetPos);
                }
            }
        }

        return(1);
    }