Пример #1
0
        public override void Apply(T map)
        {
            Grid.LocTest checkGround = (Loc testLoc) =>
            {
                if (!Collision.InBounds(map.Width, map.Height, testLoc))
                {
                    return(false);
                }
                return(map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.RoomTerrain) && !map.HasTileEffect(testLoc));
            };
            Grid.LocTest checkBlock = (Loc testLoc) =>
            {
                if (!Collision.InBounds(map.Width, map.Height, testLoc))
                {
                    return(false);
                }
                return(map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.WallTerrain));
            };

            List <LocRay4> rays = Detection.DetectWalls(((IViewPlaceableGenContext <MapGenEntrance>)map).GetLoc(0), new Rect(0, 0, map.Width, map.Height), checkBlock, checkGround);

            EffectTile    effect = new EffectTile(LockedTile, true);
            TileListState state  = new TileListState();

            effect.TileStates.Set(state);

            List <Loc> freeTiles = new List <Loc>();
            LocRay4?   ray       = PlaceRoom(map, rays, effect, freeTiles);

            if (ray != null)
            {
                PlaceEntities(map, freeTiles);
            }
        }
Пример #2
0
        /// <summary>
        /// Returns a list of wall edges with definite 4-directional normals
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="checkBlock">Determines if this is ground that can be burrowed into.</param>
        /// <param name="checkGround">Determines if this is ground that can reach a wall.</param>
        /// <returns></returns>
        public static List <LocRay4> DetectWalls(Rect rect, Grid.LocTest checkBlock, Grid.LocTest checkGround)
        {
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }

            List <LocRay4> walls = new List <LocRay4>();

            for (int xx = rect.X; xx < rect.Width; xx++)
            {
                for (int yy = rect.Y; yy < rect.Height; yy++)
                {
                    Loc testLoc = new Loc(xx, yy);
                    if (checkBlock(testLoc))
                    {
                        LocRay4 ray = GetWallDir(testLoc, checkBlock, checkGround);
                        if (ray.Dir != Dir4.None)
                        {
                            walls.Add(ray);
                        }
                    }
                }
            }

            return(walls);
        }
Пример #3
0
        public static bool IsCardinalPathBlocked(Loc start, Loc diff, Grid.LocTest checkBlock)
        {
            int sgn_x = Math.Sign(diff.X);
            int sgn_y = Math.Sign(diff.Y);

            int dx = Math.Abs(diff.X);
            int dy = Math.Abs(diff.Y);

            if (dx > 0)
            {
                for (int x = 1; x < dx; x++)
                {
                    if (checkBlock(start + new Loc(x * sgn_x, 0)))
                    {
                        return(true);
                    }
                }
            }
            else
            {
                for (int y = 1; y < dy; y++)
                {
                    if (checkBlock(start + new Loc(0, y * sgn_y)))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #4
0
        List <Loc> IGroupPlaceableGenContext <Team> .GetFreeTiles(Rect rect)
        {
            Grid.LocTest checkOp = (Loc testLoc) =>
            {
                return(canPlaceItemTile(testLoc));
            };

            return(Grid.FindTilesInBox(rect.Start, rect.Size, checkOp));
        }
Пример #5
0
        protected List <Loc> getOpenItemTiles(Rect rect)
        {
            Grid.LocTest checkOp = (Loc testLoc) =>
            {
                return(canPlaceItemTile(testLoc));
            };

            return(Grid.FindTilesInBox(rect.Start, rect.Size, checkOp));
        }
Пример #6
0
        public static LocRay4 GetWallDir(Loc loc, Grid.LocTest checkBlock, Grid.LocTest checkGround)
        {
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }
            if (checkGround == null)
            {
                throw new ArgumentNullException(nameof(checkGround));
            }

            // check the four directions
            Dir4 chosenDir = Dir4.None;

            // ensure that there is only one direction where it is unblocked
            foreach (Dir4 dir in DirExt.VALID_DIR4)
            {
                Loc newLoc = loc + dir.GetLoc();
                if (checkGround(newLoc))
                {
                    if (chosenDir != Dir4.None)
                    {
                        return(new LocRay4(loc));
                    }
                    else
                    {
                        chosenDir = dir.Reverse();
                    }
                }
                else if (!checkBlock(newLoc))
                {
                    // all four directions must be valid ground, or valid block
                    return(new LocRay4(loc));
                }
            }

            if (chosenDir == Dir4.None)
            {
                return(new LocRay4(loc));
            }

            // then check to make sure that the left and right diagonal of this direction are also valid blocked
            Loc lLoc = loc + DirExt.AddAngles(chosenDir.ToDir8(), Dir8.DownLeft).GetLoc();

            if (!checkBlock(lLoc))
            {
                return(new LocRay4(loc));
            }
            Loc rLoc = loc + DirExt.AddAngles(chosenDir.ToDir8(), Dir8.DownRight).GetLoc();

            if (!checkBlock(rLoc))
            {
                return(new LocRay4(loc));
            }

            return(new LocRay4(loc, chosenDir));
        }
Пример #7
0
        /// <summary>
        /// Returns a list of wall edges with definite 4-directional normals, connected to a start position
        /// </summary>
        /// <param name="start"></param>
        /// <param name="rect"></param>
        /// <param name="checkBlock">Determines if this is ground that can be burrowed into.</param>
        /// <param name="checkGround">Determines if this is ground that can reach a wall.</param>
        /// <returns></returns>
        public static List <LocRay4> DetectWalls(Loc start, Rect rect, Grid.LocTest checkBlock, Grid.LocTest checkGround)
        {
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }
            if (checkGround == null)
            {
                throw new ArgumentNullException(nameof(checkGround));
            }

            bool[][] checkGrid = new bool[rect.Width][];
            bool[][] fillGrid  = new bool[rect.Width][];
            for (int xx = 0; xx < rect.Width; xx++)
            {
                checkGrid[xx] = new bool[rect.Height];
                fillGrid[xx]  = new bool[rect.Height];
            }

            List <LocRay4> walls = new List <LocRay4>();

            // scan and find solely-facing walls
            // cache already-checked walls since flood fill occasionally checks twice
            Grid.FloodFill(
                rect,
                (Loc testLoc) =>
            {
                if (fillGrid[testLoc.X][testLoc.Y])
                {
                    return(true);
                }
                if (!checkGrid[testLoc.X][testLoc.Y] && checkBlock(testLoc))
                {
                    LocRay4 ray = GetWallDir(testLoc, checkBlock, checkGround);
                    if (ray.Dir != Dir4.None)
                    {
                        walls.Add(ray);
                    }
                }

                checkGrid[testLoc.X][testLoc.Y] = true;
                return(!checkGround(testLoc));
            },
                (Loc testLoc) => true,
                (Loc fillLoc) => fillGrid[fillLoc.X][fillLoc.Y] = true,
                start);

            return(walls);
        }
Пример #8
0
        private List <Loc> getOpenEntranceExitTiles(Rect rect)
        {
            List <Loc> tiles = getOpenItemTiles(rect);

            if (tiles.Count > 0)
            {
                return(tiles);
            }

            Grid.LocTest checkLenient = (Loc testLoc) =>
            {
                return(Tiles[testLoc.X][testLoc.Y].TileEquivalent(RoomTerrain));
            };

            tiles = Grid.FindTilesInBox(rect.Start, rect.Size, checkLenient);
            return(tiles);
        }
Пример #9
0
 private bool CanPlaceRect(T map, Rect rect, Grid.LocTest checkBlock)
 {
     for (int ii = rect.Left; ii < rect.Right; ii++)
     {
         for (int jj = rect.Top; jj < rect.Bottom; jj++)
         {
             Loc testLoc = new Loc(ii, jj);
             if (!Collision.InBounds(map.Width, map.Height, testLoc))
             {
                 return(false);
             }
             if (!checkBlock(testLoc))
             {
                 return(false);
             }
         }
     }
     return(true);
 }
Пример #10
0
        public static BlobMap DetectBlobs(Rect rect, Grid.LocTest isValid)
        {
            if (isValid == null)
            {
                throw new ArgumentNullException(nameof(isValid));
            }

            var blobMap = new BlobMap(rect.Width, rect.Height);

            for (int xx = rect.X; xx < rect.End.X; xx++)
            {
                for (int yy = rect.Y; yy < rect.End.Y; yy++)
                {
                    if (isValid(new Loc(xx, yy)) && blobMap.Map[xx][yy] == -1)
                    {
                        var blob = new BlobMap.Blob(new Rect(xx, yy, 1, 1), 0);

                        // fill the area, keeping track of the total area and blob bounds
                        Grid.FloodFill(
                            rect,
                            (Loc testLoc) => (!isValid(testLoc) || blobMap.Map[testLoc.X][testLoc.Y] != -1),
                            (Loc testLoc) => true,
                            (Loc fillLoc) =>
                        {
                            blobMap.Map[fillLoc.X][fillLoc.Y] = blobMap.Blobs.Count;
                            blob.Bounds = Rect.IncludeLoc(blob.Bounds, fillLoc);
                            blob.Area  += 1;
                        },
                            new Loc(xx, yy));

                        blobMap.Blobs.Add(blob);
                    }
                }
            }

            return(blobMap);
        }
Пример #11
0
        public static bool IsInFOV(Loc start, Loc end, Grid.LocTest checkBlock)
        {
            Loc diff = end - start;
            int dx   = Math.Abs(diff.X);
            int dy   = Math.Abs(diff.Y);

            if (dx <= 1 && dy <= 1)
            {
                return(true);
            }

            if (start.Y == end.Y || start.X == end.X)
            {
                return(!IsCardinalPathBlocked(start, diff, checkBlock));
            }
            else
            {
                //signs
                int sgn_x = Math.Sign(diff.X);
                int sgn_y = Math.Sign(diff.Y);
                //xy swiz

                if (dy > dx)
                {
                    return(IsPathClear(start, 1, dy, dx, 0, sgn_x, sgn_y, 0,
                                       (dx * SLOPE_GRANULARITY + SLOPE_GRANULARITY / 2) * 2 / (dy * 2 - 1),
                                       (dx * SLOPE_GRANULARITY - SLOPE_GRANULARITY / 2) * 2 / (dy * 2 + 1), checkBlock));
                }
                else
                {
                    return(IsPathClear(start, 1, dx, dy, sgn_x, 0, 0, sgn_y,
                                       (dy * SLOPE_GRANULARITY + SLOPE_GRANULARITY / 2) * 2 / (dx * 2 - 1),
                                       (dy * SLOPE_GRANULARITY - SLOPE_GRANULARITY / 2) * 2 / (dx * 2 + 1), checkBlock));
                }
            }
        }
Пример #12
0
        public override void Apply(T map)
        {
            if (Spawns.Count > 0)
            {
                List <Loc> freeTiles = new List <Loc>();
                //get all places that traps are eligible
                for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++)
                {
                    IRoomGen room = map.RoomPlan.GetRoom(ii);

                    List <Loc> tiles = ((IPlaceableGenContext <EffectTile>)map).GetFreeTiles(room.Draw);

                    freeTiles.AddRange(tiles);
                }

                // add tile
                if (freeTiles.Count > 0)
                {
                    int        randIndex   = ((IGenContext)map).Rand.Next(freeTiles.Count);
                    Loc        loc         = freeTiles[randIndex];
                    EffectTile spawnedTrap = Spawns.Pick(((IGenContext)map).Rand);
                    map.PlaceItem(loc, spawnedTrap);
                    freeTiles.RemoveAt(randIndex);

                    if (GuardSpawns.Count > 0)
                    {
                        for (int ii = 0; ii < 10; ii++)
                        {
                            Team newTeam = GuardSpawns.Pick(((IGenContext)map).Rand).Spawn(map);
                            if (newTeam == null)
                            {
                                continue;
                            }
                            //spawn guards

                            Grid.LocTest checkSpawnOpen = (Loc testLoc) =>
                            {
                                return(((IGroupPlaceableGenContext <Team>)map).CanPlaceItem(testLoc));
                            };
                            Grid.LocTest checkSpawnBlock = (Loc testLoc) =>
                            {
                                return(map.TileBlocked(testLoc));
                            };
                            Grid.LocTest checkDiagSpawnBlock = (Loc testLoc) =>
                            {
                                return(map.TileBlocked(testLoc, true));
                            };

                            List <Loc> resultLocs = new List <Loc>();
                            foreach (Loc resultLoc in Grid.FindClosestConnectedTiles(new Loc(), new Loc(map.Width, map.Height),
                                                                                     checkSpawnOpen, checkSpawnBlock, checkDiagSpawnBlock, loc, newTeam.MemberGuestCount))
                            {
                                resultLocs.Add(resultLoc);
                            }

                            if (resultLocs.Count >= newTeam.MemberGuestCount)
                            {
                                Loc[] locs = new Loc[newTeam.MemberGuestCount];
                                for (int jj = 0; jj < locs.Length; jj++)
                                {
                                    locs[jj] = resultLocs[jj];
                                }
                                map.PlaceItems(newTeam, locs);
                                break;
                            }
                        }
                    }
                }
            }
        }
Пример #13
0
        public override void Apply(T map)
        {
            Grid.LocTest checkBlock = (Loc testLoc) =>
            {
                return(!map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.RoomTerrain) || map.HasTileEffect(testLoc));
            };

            //choose a room to put the chest in
            //do not choose a room that would cause disconnection of the floor
            List <int> possibleRooms = new List <int>();

            for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++)
            {
                FloorRoomPlan testPlan = map.RoomPlan.GetRoomPlan(ii);
                //if (map.RoomPlan.IsChokePoint(new RoomHallIndex(ii, false)))
                //    continue;
                if (!BaseRoomFilter.PassesAllFilters(testPlan, this.Filters))
                {
                    continue;
                }

                //also do not choose a room that contains the end stairs
                IViewPlaceableGenContext <MapGenExit> exitMap = (IViewPlaceableGenContext <MapGenExit>)map;
                if (Collision.InBounds(testPlan.RoomGen.Draw, exitMap.GetLoc(0)))
                {
                    continue;
                }

                possibleRooms.Add(ii);
            }

            if (possibleRooms.Count == 0)
            {
                return;
            }

            List <Loc> freeTiles = new List <Loc>();
            IRoomGen   room      = null;

            while (possibleRooms.Count > 0)
            {
                int chosenRoom = map.Rand.Next(possibleRooms.Count);
                room = map.RoomPlan.GetRoom(possibleRooms[chosenRoom]);

                //get all places that the chest is eligible
                freeTiles = Grid.FindTilesInBox(room.Draw.Start, room.Draw.Size, (Loc testLoc) =>
                {
                    if (map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.RoomTerrain) && !map.HasTileEffect(testLoc) &&
                        map.Tiles[testLoc.X][testLoc.Y + 1].TileEquivalent(map.RoomTerrain) && !map.HasTileEffect(new Loc(testLoc.X, testLoc.Y + 1)) &&
                        !map.PostProcGrid[testLoc.X][testLoc.Y].Status[(int)PostProcType.Panel] &&
                        !map.PostProcGrid[testLoc.X][testLoc.Y].Status[(int)PostProcType.Item])
                    {
                        if (Grid.GetForkDirs(testLoc, checkBlock, checkBlock).Count < 2)
                        {
                            foreach (MapItem item in map.Items)
                            {
                                if (item.TileLoc == testLoc)
                                {
                                    return(false);
                                }
                            }
                            foreach (Team team in map.AllyTeams)
                            {
                                foreach (Character testChar in team.EnumerateChars())
                                {
                                    if (testChar.CharLoc == testLoc)
                                    {
                                        return(false);
                                    }
                                }
                            }
                            foreach (Team team in map.MapTeams)
                            {
                                foreach (Character testChar in team.EnumerateChars())
                                {
                                    if (testChar.CharLoc == testLoc)
                                    {
                                        return(false);
                                    }
                                }
                            }
                            return(true);
                        }
                    }
                    return(false);
                });
                if (freeTiles.Count > 0)
                {
                    break;
                }
                possibleRooms.RemoveAt(chosenRoom);
            }

            //can't find any free tile in any room, return
            if (freeTiles.Count == 0)
            {
                return;
            }

            if (!ItemThemes.CanPick)
            {
                return;
            }
            //choose which item theme to work with
            ItemTheme chosenItemTheme = ItemThemes.Pick(map.Rand);

            //the item spawn list in this class dictates the items available for spawning
            //it will be queried for items that match the theme selected
            List <MapItem> chosenItems = chosenItemTheme.GenerateItems(map, Items);

            if (chosenItems.Count == 0)
            {
                return;
            }

            int randIndex = map.Rand.Next(freeTiles.Count);
            Loc loc       = freeTiles[randIndex];


            EffectTile spawnedChest = new EffectTile(37, true);

            if (Ambush && MobThemes.CanPick)
            {
                spawnedChest.Danger = true;
                //the mob theme will be selected randomly
                MobTheme chosenMobTheme = MobThemes.Pick(map.Rand);

                //the mobs in this class are the ones that would be available when the game wants to spawn things outside of the floor's spawn list
                //it will be queried for monsters that match the theme provided
                List <MobSpawn> chosenMobs = chosenMobTheme.GenerateMobs(map, Mobs);


                MobSpawnState mobSpawn = new MobSpawnState();
                foreach (MobSpawn mob in chosenMobs)
                {
                    MobSpawn copyMob = mob.Copy();
                    if (map.Rand.Next(ALT_COLOR_ODDS) == 0)
                    {
                        copyMob.BaseForm.Skin = 1;
                    }
                    mobSpawn.Spawns.Add(copyMob);
                }
                spawnedChest.TileStates.Set(mobSpawn);
            }

            ItemSpawnState itemSpawn = new ItemSpawnState();

            itemSpawn.Spawns = chosenItems;
            spawnedChest.TileStates.Set(itemSpawn);

            Rect wallBounds = new Rect(room.Draw.X - 1, room.Draw.Y - 1, room.Draw.Size.X + 2, room.Draw.Size.Y + 2);

            spawnedChest.TileStates.Set(new BoundsState(wallBounds));

            ((IPlaceableGenContext <EffectTile>)map).PlaceItem(loc, spawnedChest);
            map.PostProcGrid[loc.X][loc.Y].Status[(int)PostProcType.Panel] = true;
            map.PostProcGrid[loc.X][loc.Y].Status[(int)PostProcType.Item]  = true;

            GenContextDebug.DebugProgress("Placed Chest");
        }
Пример #14
0
        public static bool IsPathClear(Loc start, int startCol, int endCol, int endRow, int xx, int xy, int yx, int yy, int startSlope, int endSlope, Grid.LocTest checkBlock)
        {
            bool prevBlocked = false;

            int savedRightSlope = -SLOPE_GRANULARITY;

            for (int currentCol = startCol; currentCol <= endCol; currentCol++)
            {
                int xc = currentCol;

                for (int yc = currentCol; yc >= 0; yc--)
                {
                    int gridX = start.X + xc * xx + yc * xy;
                    int gridY = start.Y + xc * yx + yc * yy;


                    int leftBlockSlope  = (yc * SLOPE_GRANULARITY + SLOPE_GRANULARITY / 2) * 2 / (xc * 2 - 1);
                    int rightBlockSlope = (yc * SLOPE_GRANULARITY - SLOPE_GRANULARITY / 2) * 2 / (xc * 2 + 1);

                    if (rightBlockSlope > startSlope) // Block is above the left edge of our view area; skip.
                    {
                        continue;
                    }
                    else if (leftBlockSlope < endSlope) // Block is below the right edge of our view area; we're done.
                    {
                        break;
                    }

                    if (currentCol == endCol && yc == endRow)
                    {
                        return(true);
                    }

                    bool curBlocked = checkBlock(new Loc(gridX, gridY));

                    if (prevBlocked)
                    {
                        if (curBlocked)
                        {
                            savedRightSlope = rightBlockSlope;
                        }
                        else
                        {
                            prevBlocked = false;
                            startSlope  = savedRightSlope;
                        }
                    }
                    else
                    {
                        if (curBlocked)
                        {
                            if (leftBlockSlope <= startSlope)
                            {
                                if (IsPathClear(start, currentCol + 1, endCol, endRow, xx, xy, yx, yy, startSlope, leftBlockSlope, checkBlock))
                                {
                                    return(true);
                                }
                            }

                            prevBlocked     = true;
                            savedRightSlope = rightBlockSlope;
                        }
                    }
                }

                if (prevBlocked)
                {
                    break;
                }
            }
            return(false);
        }
Пример #15
0
        /// <summary>
        /// Detects if an added blob disconnects the map's existing connectivity.
        /// </summary>
        /// <param name="mapBounds"></param>
        /// <param name="isMapValid">Checks for a valid path tile.</param>
        /// <param name="blobDest">Position to draw the blob at.</param>
        /// <param name="blobSize"></param>
        /// <param name="isBlobValid">Checks for a valid blob tile. Loc is with respect to the top right of the blob rect.</param>
        /// <param name="countErasures">Whether a completely erased graph counts as disconnected or not.</param>
        /// <returns></returns>
        public static bool DetectDisconnect(Rect mapBounds, Grid.LocTest isMapValid, Loc blobDest, Loc blobSize, Grid.LocTest isBlobValid, bool countErasures)
        {
            if (isMapValid == null)
            {
                throw new ArgumentNullException(nameof(isMapValid));
            }
            if (isBlobValid == null)
            {
                throw new ArgumentNullException(nameof(isBlobValid));
            }

            List <int> mapBlobCounts = new List <int>();

            int[][] fullGrid  = new int[mapBounds.Width][];
            int[][] splitGrid = new int[mapBounds.Width][];
            for (int xx = 0; xx < mapBounds.Width; xx++)
            {
                fullGrid[xx]  = new int[mapBounds.Height];
                splitGrid[xx] = new int[mapBounds.Height];
                for (int yy = 0; yy < mapBounds.Height; yy++)
                {
                    fullGrid[xx][yy]  = -1;
                    splitGrid[xx][yy] = -1;
                }
            }

            // iterate the map and flood fill when finding a walkable.
            // Count the number of times a flood fill is required.  This is the blob count.
            for (int xx = 0; xx < mapBounds.Width; xx++)
            {
                for (int yy = 0; yy < mapBounds.Height; yy++)
                {
                    if (isMapValid(new Loc(xx, yy)) && fullGrid[xx][yy] == -1)
                    {
                        int totalFill = 0;
                        Grid.FloodFill(
                            new Rect(0, 0, mapBounds.Width, mapBounds.Height),
                            (Loc testLoc) => (fullGrid[testLoc.X][testLoc.Y] == mapBlobCounts.Count) || !isMapValid(testLoc),
                            (Loc testLoc) => true,
                            (Loc fillLoc) =>
                        {
                            fullGrid[fillLoc.X][fillLoc.Y] = mapBlobCounts.Count;
                            totalFill++;
                        },
                            new Loc(xx, yy));
                        mapBlobCounts.Add(totalFill);
                    }
                }
            }

            // we've passed in a boolean grid containing a blob, with an offset of where to render it to
            for (int xx = Math.Max(0, blobDest.X); xx < Math.Min(mapBounds.Width, blobDest.X + blobSize.X); xx++)
            {
                for (int yy = Math.Max(0, blobDest.Y); yy < Math.Min(mapBounds.Height, blobDest.Y + blobSize.Y); yy++)
                {
                    int blobIndex = fullGrid[xx][yy];
                    if (blobIndex > -1 && isBlobValid(new Loc(xx, yy) - blobDest))
                    {
                        mapBlobCounts[blobIndex] = mapBlobCounts[blobIndex] - 1;
                        fullGrid[xx][yy]         = -1;
                    }
                }
            }

            // remove the blobs that have been entirely erased; return false if entirely erased.
            for (int ii = mapBlobCounts.Count - 1; ii >= 0; ii--)
            {
                if (mapBlobCounts[ii] == 0)
                {
                    if (countErasures)
                    {
                        return(true);
                    }
                    mapBlobCounts.RemoveAt(ii);
                }
            }

            // iterate the map and flood fill when finding a walkable (needs a new bool grid), this time discounting tiles involved in the blob.  count times needed for this
            int blobsFound = 0;

            for (int xx = 0; xx < mapBounds.Width; xx++)
            {
                for (int yy = 0; yy < mapBounds.Height; yy++)
                {
                    if (fullGrid[xx][yy] > -1 && splitGrid[xx][yy] == -1)
                    {
                        Grid.FloodFill(
                            new Rect(0, 0, mapBounds.Width, mapBounds.Height),
                            (Loc testLoc) => (splitGrid[testLoc.X][testLoc.Y] == blobsFound) || (fullGrid[testLoc.X][testLoc.Y] == -1),
                            (Loc testLoc) => true,
                            (Loc fillLoc) => splitGrid[fillLoc.X][fillLoc.Y] = blobsFound,
                            new Loc(xx, yy));

                        blobsFound++;
                    }
                }
            }

            // more times = more blobs = failure
            return(blobsFound != mapBlobCounts.Count);
        }
Пример #16
0
        public override void Apply(T map)
        {
            //first get all free tiles suitable for the switch
            List <Loc> freeSwitchTiles = ((IPlaceableGenContext <EffectTile>)map).GetAllFreeTiles();

            if (freeSwitchTiles.Count == 0)
            {
                return;
            }

            Grid.LocTest checkGround = (Loc testLoc) =>
            {
                if (!Collision.InBounds(map.Width, map.Height, testLoc))
                {
                    return(false);
                }
                return(map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.RoomTerrain) && !map.HasTileEffect(testLoc));
            };
            Grid.LocTest checkBlock = (Loc testLoc) =>
            {
                if (!Collision.InBounds(map.Width, map.Height, testLoc))
                {
                    return(false);
                }
                return(map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.WallTerrain));
            };

            List <LocRay4> rays = Detection.DetectWalls(((IViewPlaceableGenContext <MapGenEntrance>)map).GetLoc(0), new Rect(0, 0, map.Width, map.Height), checkBlock, checkGround);

            EffectTile effect = new EffectTile(SealedTile, true);

            List <Loc>     freeTiles        = new List <Loc>();
            List <LocRay4> createdEntrances = new List <LocRay4>();

            int amount = EntranceCount.Pick(map.Rand);

            for (int ii = 0; ii < amount; ii++)
            {
                LocRay4?ray = PlaceRoom(map, rays, effect, freeTiles);

                if (ray != null)
                {
                    createdEntrances.Add(ray.Value);
                }
            }

            if (createdEntrances.Count > 0)
            {
                PlaceEntities(map, freeTiles);

                EffectTile switchTile = new EffectTile(SwitchTile, true);

                if (TimeLimit)
                {
                    switchTile.Danger = true;
                }

                TileListState state = new TileListState();
                for (int mm = 0; mm < createdEntrances.Count; mm++)
                {
                    state.Tiles.Add(new Loc(createdEntrances[mm].Loc));
                }
                switchTile.TileStates.Set(state);

                int randIndex = map.Rand.Next(freeSwitchTiles.Count);

                ((IPlaceableGenContext <EffectTile>)map).PlaceItem(freeSwitchTiles[randIndex], switchTile);
            }
        }
Пример #17
0
        protected LocRay4?PlaceRoom(T map, List <LocRay4> rays, EffectTile sealingTile, List <Loc> freeTiles)
        {
            Grid.LocTest checkBlockForPlace = (Loc testLoc) =>
            {
                if (!Collision.InBounds(map.Width, map.Height, testLoc))
                {
                    return(false);
                }
                return(!map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.RoomTerrain) && !map.Tiles[testLoc.X][testLoc.Y].TileEquivalent(map.UnbreakableTerrain));
            };
            //try X times to dig a passage
            for (int ii = 0; ii < 500 && rays.Count > 0; ii++)
            {
                int     rayIndex = map.Rand.Next(rays.Count);
                LocRay4 ray      = rays[rayIndex];
                rays.RemoveAt(rayIndex);

                Loc   rayDirLoc = ray.Dir.GetLoc();
                Axis4 axis      = ray.Dir.ToAxis();
                Axis4 orth      = axis == Axis4.Horiz ? Axis4.Vert : Axis4.Horiz;

                int  minLength = Math.Max(1, HallLength.Min);
                Rect hallBound = new Rect(ray.Loc + DirExt.AddAngles(ray.Dir, Dir4.Left).GetLoc(), new Loc(1));
                hallBound = Rect.IncludeLoc(hallBound, ray.Loc + rayDirLoc * (minLength - 1) + DirExt.AddAngles(ray.Dir, Dir4.Right).GetLoc());

                //make sure the MIN hall can tunnel unimpeded
                if (!CanPlaceRect(map, hallBound, checkBlockForPlace))
                {
                    continue;
                }

                for (int jj = 0; jj < 100; jj++)
                {
                    //plan the room
                    RoomGen <T> plan = GenericRooms.Pick(map.Rand).Copy();
                    Loc         size = plan.ProposeSize(map.Rand);
                    plan.PrepareSize(map.Rand, size);
                    //attempt to place the bounds somewhere, anywhere, within the limitations that the room itself provides
                    List <int> candidateOpenings = new List <int>();
                    int        planLength        = plan.GetBorderLength(ray.Dir.Reverse());
                    for (int kk = 0; kk < planLength; kk++)
                    {
                        if (plan.GetFulfillableBorder(ray.Dir.Reverse(), kk))
                        {
                            candidateOpenings.Add(kk);
                        }
                    }

                    //as well as continue extending the hall until we hit a walkable.
                    int tunnelLen  = Math.Max(1, HallLength.Pick(map.Rand));
                    Loc roomLoc    = ray.Loc + rayDirLoc * tunnelLen;
                    int perpOffset = candidateOpenings[map.Rand.Next(candidateOpenings.Count)];
                    roomLoc += orth.CreateLoc(-perpOffset, 0);
                    if (rayDirLoc.GetScalar(axis) < 0)//move back the top-left of the entrance
                    {
                        roomLoc += rayDirLoc * (size.GetScalar(axis) - 1);
                    }

                    Rect roomTestBound = new Rect(roomLoc, size);
                    roomTestBound.Inflate(1, 1);
                    //make a rect for the rest of the hall
                    Rect hallExtBound = new Rect(ray.Loc + rayDirLoc * minLength + DirExt.AddAngles(ray.Dir, Dir4.Left).GetLoc(), new Loc(1));
                    hallExtBound = Rect.IncludeLoc(hallBound, ray.Loc + rayDirLoc * (tunnelLen - 1) + DirExt.AddAngles(ray.Dir, Dir4.Right).GetLoc());
                    //now that we've chosen our position, let's test it
                    if (!CanPlaceRect(map, roomTestBound, checkBlockForPlace) || !CanPlaceRect(map, hallExtBound, checkBlockForPlace)) // also test that the CHOSEN hallway can be properly sealed
                    {
                        continue;                                                                                                      //invalid location, try another place
                    }
                    else
                    {
                        plan.SetLoc(roomLoc);

                        plan.ReceiveBorderRange(new IntRange(perpOffset, perpOffset + 1) + roomLoc.GetScalar(orth), ray.Dir.Reverse());
                        //draw the room
                        plan.DrawOnMap(map);

                        //surround the room with bounds
                        for (int xx = roomTestBound.X; xx < roomTestBound.Right; xx++)
                        {
                            map.Tiles[xx][roomTestBound.Y]         = (Tile)map.UnbreakableTerrain.Copy();
                            map.Tiles[xx][roomTestBound.End.Y - 1] = (Tile)map.UnbreakableTerrain.Copy();
                        }
                        for (int yy = roomTestBound.Y + 1; yy < roomTestBound.Bottom - 1; yy++)
                        {
                            map.Tiles[roomTestBound.X][yy]         = (Tile)map.UnbreakableTerrain.Copy();
                            map.Tiles[roomTestBound.End.X - 1][yy] = (Tile)map.UnbreakableTerrain.Copy();
                        }

                        //spawn tiles, items, foes
                        List <Loc> addedTiles = ((IPlaceableGenContext <MapItem>)map).GetFreeTiles(plan.Draw);
                        freeTiles.AddRange(addedTiles);


                        //tunnel to the room
                        Loc loc = ray.Loc;
                        for (int tt = 0; tt < tunnelLen; tt++)
                        {
                            //make walkable
                            map.Tiles[loc.X][loc.Y] = (Tile)map.RoomTerrain.Copy();

                            //make left side unbreakable
                            Loc lLoc = loc + DirExt.AddAngles(ray.Dir, Dir4.Left).GetLoc();
                            map.Tiles[lLoc.X][lLoc.Y] = (Tile)map.UnbreakableTerrain.Copy();

                            //make right side unbreakable
                            Loc rLoc = loc + DirExt.AddAngles(ray.Dir, Dir4.Right).GetLoc();
                            map.Tiles[rLoc.X][rLoc.Y] = (Tile)map.UnbreakableTerrain.Copy();

                            loc += rayDirLoc;
                        }

                        //finally, seal with a locked door
                        map.Tiles[ray.Loc.X][ray.Loc.Y] = (Tile)map.UnbreakableTerrain.Copy();
                        EffectTile newEffect = new EffectTile(sealingTile, ray.Loc);
                        ((IPlaceableGenContext <EffectTile>)map).PlaceItem(ray.Loc, newEffect);

                        return(ray);
                    }
                }
            }

            //DiagManager.Instance.LogInfo("Couldn't place sealed detour!");

            return(null);
        }
Пример #18
0
        public static void CalculateAnalogFOV(Loc rectStart, Loc rectSize, Loc start, Grid.LocTest checkBlock, LightOperation lightOp)
        {
            // Viewer's cell is always visible.
            if (Collision.InBounds(rectStart, rectSize, start))
            {
                lightOp(start.X, start.Y, 1f);
            }

            for (int dir = 0; dir < DirExt.DIR8_COUNT; dir++)
            {
                CastPartialLight(rectStart, rectSize, start, checkBlock, lightOp, 1, 3 * SLOPE_GRANULARITY, -SLOPE_GRANULARITY, (Dir8)dir);
            }
        }
Пример #19
0
        private static void CastPartialLight(Loc rectStart, Loc rectSize, Loc start, Grid.LocTest checkBlock, LightOperation lightOp, int startColumn, int startSlope, int endSlope, Dir8 dir)
        {
            // Set true if the previous cell we encountered was blocked.
            bool prevBlocked = false;

            int savedRightSlope = -SLOPE_GRANULARITY;

            int colVal = OctantTransform[(int)dir, 0] != 0 ? OctantTransform[(int)dir, 0] : OctantTransform[(int)dir, 2];

            Loc colDiff = new Loc();

            if (colVal > 0)
            {
                colDiff = rectStart + rectSize - start - new Loc(1);
            }
            else
            {
                colDiff = start - rectStart;
            }

            int maxCol = OctantTransform[(int)dir, 0] != 0 ? colDiff.X : colDiff.Y;

            int rowVal  = OctantTransform[(int)dir, 3] != 0 ? OctantTransform[(int)dir, 3] : OctantTransform[(int)dir, 1];
            Loc rowDiff = new Loc();

            if (rowVal > 0)
            {
                rowDiff = rectStart + rectSize - start - new Loc(1);
            }
            else
            {
                rowDiff = start - rectStart;
            }
            int maxRow = OctantTransform[(int)dir, 3] != 0 ? rowDiff.Y : rowDiff.X;

            for (int currentCol = startColumn; currentCol <= maxCol; currentCol++)
            {
                int xc = currentCol;

                for (int yc = Math.Min(maxRow, currentCol); yc >= 0; yc--)
                {
                    int gridX = start.X + xc * OctantTransform[(int)dir, 0] + yc * OctantTransform[(int)dir, 1];
                    int gridY = start.Y + xc * OctantTransform[(int)dir, 2] + yc * OctantTransform[(int)dir, 3];

                    //due to safeguards, this block should never be hit
                    if (!Collision.InBounds(rectStart, rectSize, new Loc(gridX, gridY)))
                    {
                        continue;
                    }

                    int leftBlockSlope  = (yc * SLOPE_GRANULARITY + SLOPE_GRANULARITY / 2) * 2 / (xc * 2 - 1);
                    int rightBlockSlope = (yc * SLOPE_GRANULARITY - SLOPE_GRANULARITY / 2) * 2 / (xc * 2 + 1);

                    if (rightBlockSlope > startSlope) // Block is above the left edge of our view area; skip.
                    {
                        continue;
                    }
                    else if (leftBlockSlope < endSlope) // Block is below the right edge of our view area; we're done.
                    {
                        break;
                    }

                    float lighting = 1f;
                    if (leftBlockSlope > startSlope) // Block is above the left edge of our view area; skip.
                    {
                        lighting = 0.5f;
                    }
                    else if (rightBlockSlope < endSlope) // Block is below the right edge of our view area; we're done.
                    {
                        lighting = 0.5f;
                    }

                    if (((int)dir % 2 == 0 || yc != 0) && ((int)dir % 2 == 1 || yc != currentCol))
                    {
                        lightOp(gridX, gridY, lighting);
                    }

                    bool curBlocked = checkBlock(new Loc(gridX, gridY));

                    if (prevBlocked)
                    {
                        if (curBlocked)
                        {
                            savedRightSlope = rightBlockSlope;
                        }
                        else
                        {
                            prevBlocked = false;
                            startSlope  = savedRightSlope;
                        }
                    }
                    else
                    {
                        if (curBlocked)
                        {
                            if (leftBlockSlope <= startSlope)
                            {
                                CastPartialLight(rectStart, rectSize, start, checkBlock, lightOp, currentCol + 1, startSlope, leftBlockSlope, dir);
                            }

                            prevBlocked     = true;
                            savedRightSlope = rightBlockSlope;
                        }
                    }
                }

                if (prevBlocked)
                {
                    break;
                }
            }
        }
Пример #20
0
        public List <Character> RespawnMob()
        {
            List <Character> respawns = new List <Character>();

            if (TeamSpawns.Count > 0)
            {
                bool[][] traversedGrid = new bool[Width][];
                for (int xx = 0; xx < Width; xx++)
                {
                    traversedGrid[xx] = new bool[Height];
                }

                List <Loc> freeTiles = new List <Loc>();
                Grid.FloodFill(new Rect(new Loc(), new Loc(Width, Height)),
                               (Loc testLoc) =>
                {
                    if (traversedGrid[testLoc.X][testLoc.Y])
                    {
                        return(true);
                    }
                    return(TileBlocked(testLoc));
                },
                               (Loc testLoc) =>
                {
                    if (traversedGrid[testLoc.X][testLoc.Y])
                    {
                        return(true);
                    }
                    return(TileBlocked(testLoc, true));
                },
                               (Loc testLoc) =>
                {
                    traversedGrid[testLoc.X][testLoc.Y] = true;

                    //must be walkable, not have a nonwalkable on at least 3 cardinal directions, not be within eyesight of any of the player characters
                    foreach (Character character in ActiveTeam.Players)
                    {
                        if (character.IsInSightBounds(testLoc))
                        {
                            return;
                        }
                    }

                    foreach (Team team in MapTeams)
                    {
                        foreach (Character character in team.Players)
                        {
                            if (!character.Dead && character.CharLoc == testLoc)
                            {
                                return;
                            }
                        }
                    }
                    freeTiles.Add(testLoc);
                },
                               EntryPoints[0].Loc);

                if (freeTiles.Count > 0)
                {
                    for (int ii = 0; ii < 10; ii++)
                    {
                        Team newTeam = TeamSpawns.Pick(Rand).Spawn(this);
                        if (newTeam == null)
                        {
                            continue;
                        }
                        Loc trialLoc = freeTiles[Rand.Next(freeTiles.Count)];
                        //find a way to place all members- needs to fit all of them in, or else fail the spawn

                        Grid.LocTest checkOpen = (Loc testLoc) =>
                        {
                            if (TileBlocked(testLoc))
                            {
                                return(false);
                            }

                            Character locChar = GetCharAtLoc(testLoc);
                            if (locChar != null)
                            {
                                return(false);
                            }
                            return(true);
                        };
                        Grid.LocTest checkBlock = (Loc testLoc) =>
                        {
                            return(TileBlocked(testLoc, true));
                        };
                        Grid.LocTest checkDiagBlock = (Loc testLoc) =>
                        {
                            return(TileBlocked(testLoc, true, true));
                        };

                        List <Loc> resultLocs = new List <Loc>();
                        foreach (Loc loc in Grid.FindClosestConnectedTiles(new Loc(), new Loc(Width, Height),
                                                                           checkOpen, checkBlock, checkDiagBlock, trialLoc, newTeam.Players.Count))
                        {
                            resultLocs.Add(loc);
                        }


                        if (resultLocs.Count >= newTeam.Players.Count)
                        {
                            for (int jj = 0; jj < newTeam.Players.Count; jj++)
                            {
                                newTeam.Players[jj].CharLoc = resultLocs[jj];
                            }

                            MapTeams.Add(newTeam);

                            foreach (Character member in newTeam.Players)
                            {
                                member.RefreshTraits();
                                respawns.Add(member);
                            }
                            break;
                        }
                    }
                }
            }
            return(respawns);
        }
Пример #21
0
        private GameAction DumbAvoid(Character controlledChar, bool preThink, List <Character> seenCharacters, CharIndex ownIndex, IRandom rand)
        {
            StablePriorityQueue <double, Dir8> candidateDirs = new StablePriorityQueue <double, Dir8>();

            //choose the single direction that avoids other characters the most
            bool respectPeers = !preThink;

            for (int ii = -1; ii < DirExt.DIR8_COUNT; ii++)
            {
                Loc checkLoc = controlledChar.CharLoc + ((Dir8)ii).GetLoc();

                double dirDistance = 0;
                //iterated in increasing character indices
                foreach (Character seenChar in seenCharacters)
                {
                    if (RunFromAllies && !RunFromFoes)
                    {
                        //only avoid if their character index is lower than this one, aka higher ranking member
                        CharIndex seenIndex = ZoneManager.Instance.CurrentMap.GetCharIndex(seenChar);
                        if (seenIndex.Team > ownIndex.Team)
                        {
                            break;
                        }
                        else if (seenIndex.Team == ownIndex.Team)
                        {
                            if (seenIndex.Char > ownIndex.Char && seenChar.MemberTeam.LeaderIndex != seenIndex.Char)
                            {
                                continue;
                            }
                        }
                    }

                    dirDistance += Math.Sqrt((checkLoc - seenChar.CharLoc).DistSquared());
                }

                candidateDirs.Enqueue(-dirDistance, (Dir8)ii);
            }


            Grid.LocTest checkDiagBlock = (Loc testLoc) =>
            {
                return(ZoneManager.Instance.CurrentMap.TileBlocked(testLoc, controlledChar.Mobility, true));
                //enemy/ally blockings don't matter for diagonals
            };

            Grid.LocTest checkBlock = (Loc testLoc) =>
            {
                if (ZoneManager.Instance.CurrentMap.TileBlocked(testLoc, controlledChar.Mobility))
                {
                    return(true);
                }

                if ((IQ & AIFlags.TrapAvoider) != AIFlags.None)
                {
                    Tile tile = ZoneManager.Instance.CurrentMap.Tiles[testLoc.X][testLoc.Y];
                    if (tile.Effect.ID > -1)
                    {
                        TileData entry = DataManager.Instance.GetTile(tile.Effect.ID);
                        if (entry.StepType == TileData.TriggerType.Trap || entry.StepType == TileData.TriggerType.Site || entry.StepType == TileData.TriggerType.Switch)
                        {
                            return(true);
                        }
                    }
                }

                if (respectPeers && BlockedByChar(testLoc, Alignment.Self | Alignment.Foe))
                {
                    return(true);
                }

                return(false);
            };

            //try each direction from most appealing to least appealing, stopping if we get to "none"
            while (candidateDirs.Count > 0)
            {
                Dir8 highestDir = candidateDirs.Dequeue();
                if (highestDir == Dir8.None)
                {
                    if (AbortIfCornered)//this plan will be aborted, try the next plan in the list
                    {
                        return(null);
                    }
                    else//cry in a corner
                    {
                        return(new GameAction(GameAction.ActionType.Wait, Dir8.None));
                    }
                }
                else
                {
                    //check to see if we can walk this way
                    if (!Grid.IsDirBlocked(controlledChar.CharLoc, highestDir, checkBlock, checkDiagBlock))
                    {
                        return(TrySelectWalk(controlledChar, highestDir));
                    }
                }
            }

            if (AbortIfCornered)//this plan will be aborted, try the next plan in the list
            {
                return(null);
            }
            else//cry in a corner
            {
                return(new GameAction(GameAction.ActionType.Wait, Dir8.None));
            }
        }