예제 #1
0
        //also do this for rectangle beams (use three of them)
        public static bool IsInMovingCircle(Loc loc, Loc origin1, Loc origin2, int radius)
        {
            if (origin1 == origin2)
            {
                return(IsInCircleSquareHitbox(loc, origin1, radius, radius, AreaLimit.Full, Dir8.Down));
            }

            //vector from origin1 to origin2
            Loc va = origin2 - origin1;

            //vector from first origin to test point
            Loc ab = loc - origin1;

            //get closest point on the line
            int a = Loc.Dot(va, ab);

            //check collision depending on where the point is projected on the line segment
            if (a < 0)
            {
                return(ab.DistSquared() <= radius); //check first origin collision
            }
            else if (a > Loc.Dot(va, va))
            {
                return((loc - origin2).DistSquared() <= radius); //check last origin collision
            }
            else
            {
                //right-angle vector
                Loc ortho = new Loc(-va.Y, va.X);
                int dist  = Loc.Dot(ortho, ab);
                return(dist <= radius && dist >= -radius);
            }
        }
예제 #2
0
        public static bool IsInSquareHitbox(Loc loc, Loc origin, int squareRadius, AreaLimit limit, Dir8 dir)
        {
            if (loc.X < origin.X - squareRadius || loc.X > origin.X + squareRadius)
            {
                return(false);
            }
            if (loc.Y < origin.Y - squareRadius || loc.Y > origin.Y + squareRadius)
            {
                return(false);
            }

            if (limit == AreaLimit.Cone)
            {
                //check if it's inside the cone

                //get line diff
                Loc diff = loc - origin;

                //get cone vectors
                Dir8 cone1 = DirExt.AddAngles(dir, Dir8.DownRight);
                Dir8 cone2 = DirExt.AddAngles(dir, Dir8.DownLeft);

                //get vector orthogonal1 to first cone line (aka, -second cone line)
                Loc ortho1 = cone2.GetLoc() * -1;

                //get vector orthogonal2 to second cone line ( aka, first cone line)
                Loc ortho2 = cone1.GetLoc();

                //get dot product of diff to orthogonal1; must be less than or equal to 0
                int dot1 = Loc.Dot(diff, ortho1);

                //get dot product of diff to orthogonal2; must be greater than or equal to 0
                int dot2 = Loc.Dot(diff, ortho2);

                if (dot1 > 0 || dot2 < 0)
                {
                    return(false);
                }
            }
            else if (limit == AreaLimit.Sides)
            {
                Loc diff = loc - origin;
                if (dir.IsDiagonal())
                {
                    //get cone vectors
                    Dir8 cone1 = DirExt.AddAngles(dir.Reverse(), Dir8.DownRight);
                    Dir8 cone2 = DirExt.AddAngles(dir.Reverse(), Dir8.DownLeft);

                    //get vector orthogonal1 to first cone line (aka, -second cone line)
                    Loc ortho1 = cone2.GetLoc() * -1;

                    //get vector orthogonal2 to second cone line ( aka, first cone line)
                    Loc ortho2 = cone1.GetLoc();

                    //get dot product of diff to orthogonal1; must be less than or equal to 0
                    int dot1 = Loc.Dot(diff, ortho1);

                    //get dot product of diff to orthogonal2; must be greater than or equal to 0
                    int dot2 = Loc.Dot(diff, ortho2);

                    if (dot1 > 0 || dot2 < 0)
                    {
                        return(false);
                    }

                    //additionally, both dot products cannot be a nonzero
                    if (dot1 != 0 && dot2 != 0)
                    {
                        return(false);
                    }
                }
                else
                {
                    //check if it's inside the sides
                    int dot = Loc.Dot(diff, dir.GetLoc());

                    //check if the other point is EXACTLY perpendicular
                    if (dot != 0)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #3
0
        public override GameAction Think(Character controlledChar, bool preThink, IRandom rand)
        {
            if (controlledChar.CantWalk)
            {
                return(null);
            }

            //remove all locs from the locHistory that are no longer on screen
            Loc seen = Character.GetSightDims();

            for (int ii = locHistory.Count - 1; ii >= 0; ii--)
            {
                Loc diff = locHistory[ii] - controlledChar.CharLoc;
                if (Math.Abs(diff.X) > seen.X || Math.Abs(diff.Y) > seen.Y || ii > 15)
                {
                    locHistory.RemoveRange(0, ii);
                    break;
                }
            }
            Loc offset = controlledChar.CharLoc - seen;

            //CHECK FOR ADVANCE
            if (goalPath.Count > 1 && goalPath[goalPath.Count - 2] == controlledChar.CharLoc) //check if we advanced since last time
            {
                goalPath.RemoveAt(goalPath.Count - 1);                                        //remove our previous trail
            }
            //check to see if the end loc is still valid... or, just check to see if *the next step* is still valid
            if (goalPath.Count > 1)
            {
                if (controlledChar.CharLoc == goalPath[goalPath.Count - 1])//check if on the trail
                {
                    if (!ZoneManager.Instance.CurrentMap.TileBlocked(goalPath[goalPath.Count - 2], controlledChar.Mobility) &&
                        !BlockedByTrap(controlledChar, goalPath[goalPath.Count - 2]) &&
                        !BlockedByHazard(controlledChar, goalPath[goalPath.Count - 2]))//check to make sure the next step didn't suddely become blocked
                    {
                        //update current traversals
                        if (locHistory.Count == 0 || locHistory[locHistory.Count - 1] != controlledChar.CharLoc)
                        {
                            locHistory.Add(controlledChar.CharLoc);
                        }
                        if (!preThink)
                        {
                            Character destChar = ZoneManager.Instance.CurrentMap.GetCharAtLoc(goalPath[goalPath.Count - 2]);
                            if (destChar != null && ZoneManager.Instance.CurrentMap.TerrainBlocked(controlledChar.CharLoc, destChar.Mobility))
                            {
                                return(new GameAction(GameAction.ActionType.Wait, Dir8.None));
                            }
                        }
                        GameAction act = TrySelectWalk(controlledChar, DirExt.GetDir(goalPath[goalPath.Count - 1], goalPath[goalPath.Count - 2]));
                        //attempt to continue the path
                        //however, we can only verify that we continued on the path on the next loop, using the CHECK FOR ADVANCE block
                        return(act);
                    }
                }
            }

            goalPath = new List <Loc>();
            //if it isn't find a new end loc
            List <Loc> seenExits = GetAreaExits(controlledChar);

            if (seenExits.Count == 0)
            {
                return(null);
            }
            //one element in the acceptable range will be randomly selected to be the one that drives the heuristic

            //later, rate the exits based on how far they are from the tail point of the lochistory
            //add them to a sorted list

            List <Loc> forwardFacingLocs = new List <Loc>();

            if (locHistory.Count > 0)
            {
                Loc pastDir = locHistory[0] - controlledChar.CharLoc;
                for (int ii = seenExits.Count - 1; ii >= 0; ii--)
                {
                    if (Loc.Dot(pastDir, (seenExits[ii] - controlledChar.CharLoc)) <= 0)
                    {
                        forwardFacingLocs.Add(seenExits[ii]);
                        seenExits.RemoveAt(ii);
                    }
                }
            }

            //if any of the tiles are reached in the search, they will be automatically chosen

            //Analysis:
            //if there is only one exit, and it's easily reached, the speed is the same - #1 fastest case
            //if there are many exits, and they're easily reached, the speed is the same - #1 fastest case
            //if there's one exit, and it's impossible, the speed is the same - #2 fastest case
            //if there's many exits, and they're all impossible, the speed is faster - #2 fastest case
            //if there's many exits, and only the backtrack is possible, the speed is faster - #2 fastest case

            //first attempt the ones that face forward
            if (forwardFacingLocs.Count > 0)
            {
                goalPath = GetRandomPathPermissive(rand, controlledChar, forwardFacingLocs);
            }

            //then attempt remaining locations
            if (goalPath.Count == 0)
            {
                goalPath = GetRandomPathPermissive(rand, controlledChar, seenExits);
            }

            if (goalPath.Count == 0)
            {
                return(null);
            }

            if (locHistory.Count == 0 || locHistory[locHistory.Count - 1] != controlledChar.CharLoc)
            {
                locHistory.Add(controlledChar.CharLoc);
            }

            //TODO: we seldom ever run into other characters who obstruct our path, but if they do, try to wait courteously for them if they are earlier on the team list than us
            //check to make sure we aren't force-warping anyone from their position
            if (!preThink && goalPath.Count > 1)
            {
                Character destChar = ZoneManager.Instance.CurrentMap.GetCharAtLoc(goalPath[goalPath.Count - 2]);
                if (destChar != null && ZoneManager.Instance.CurrentMap.TerrainBlocked(controlledChar.CharLoc, destChar.Mobility))
                {
                    return(new GameAction(GameAction.ActionType.Wait, Dir8.None));
                }
            }
            return(SelectChoiceFromPath(controlledChar, goalPath));
        }