Ejemplo n.º 1
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);
        }