public RandomDungeon(string areaPrefix, int areasToGenerate, int cr, string name, CLRScriptBase script)
{
CR = cr;
DungeonStore.FindAvailableAreas(areaPrefix);
List<RandomDungeonArea> sourceAreas = new List<RandomDungeonArea>();
if (areasToGenerate > 1)
{
foreach (RandomDungeonArea area in DungeonStore.AvailableAreas[areaPrefix])
{
if (area.AreaExits.Count <= areasToGenerate && area.AreaExits.Count > 1)
{
sourceAreas.Add(area);
}
}
}
else
{
foreach (RandomDungeonArea area in DungeonStore.AvailableAreas[areaPrefix])
{
if (area.AreaExits.Count == 1)
{
sourceAreas.Add(area);
}
}
}
RandomDungeonArea template = sourceAreas[rnd.Next(sourceAreas.Count)];
RandomDungeonArea toAdd = new RandomDungeonArea();
toAdd.TemplateAreaId = template.AreaId;
toAdd.DungeonName = name;
toAdd.AreaExits = new List<ExitDirection>();
toAdd.AreaExits.AddRange(template.AreaExits);
toAdd.DungeonExit = toAdd.AreaExits[rnd.Next(toAdd.AreaExits.Count)];
toAdd.AreaExits.Remove(toAdd.DungeonExit);
toAdd.X = areasToGenerate + 1;
toAdd.Y = areasToGenerate + 1;
toAdd.Z = areasToGenerate + 1;
toAdd.CR = cr;
areasToGenerate -= toAdd.AreaExits.Count;
areasToGenerate -= 1;
AreasOfDungeon.Add(toAdd);
List<RandomDungeonArea> areasNeedingAdjacentAreas = new List<RandomDungeonArea>();
areasNeedingAdjacentAreas.Add(toAdd);
while (areasNeedingAdjacentAreas.Count > 0)
{
// Randomly select one of our bare ends to build out from.
RandomDungeonArea toExpand = areasNeedingAdjacentAreas[rnd.Next(areasNeedingAdjacentAreas.Count)];
// Build a temporary collection of exit directions from this area, but
// don't count the directions that already have adjacent areas.
List<ExitDirection> NextAreaDirections = new List<ExitDirection>();
NextAreaDirections.AddRange(toExpand.AreaExits);
foreach(ExitDirection used in toExpand.AdjacentAreas.Keys)
{
NextAreaDirections.Remove(used);
}
if(NextAreaDirections.Count == 0)
{
// If that's all of the exits, then this area shouldn't actually be on the list
// of candidates to expand.
areasNeedingAdjacentAreas.Remove(toExpand);
continue;
}
// Pick a random direction out of those available and set the new area's coordinates
// appropriately.
ExitDirection nextAreaDirection = NextAreaDirections[rnd.Next(NextAreaDirections.Count)];
toAdd = new RandomDungeonArea();
_setAreaCoordinates(toExpand, toAdd, nextAreaDirection);
// Scan for adjacent areas, and determine the necessary parts of the target area.
Dictionary<ExitDirection, bool> necessaryBorders = new Dictionary<ExitDirection, bool>();
Dictionary<ExitDirection, RandomDungeonArea> adjacentToBe = new Dictionary<ExitDirection, RandomDungeonArea>();
_buildBorders(necessaryBorders, adjacentToBe, toAdd);
// If we can't generate more areas, order the new areas to not open up any more exits that we'd have to
// attach areas to. Future additions will just be attaching things to dangling ATs.
if(areasToGenerate <= 0) _sealBorders(necessaryBorders);
// Now that we know where the area is and what borders it has to maintain, we
// loop through the areas that are available and build a list of all of the ones
// that fit the restrictions of the area's location.
sourceAreas.Clear();
foreach(RandomDungeonArea area in DungeonStore.AvailableAreas[areaPrefix])
{
bool areaUseful = true;
foreach(KeyValuePair<ExitDirection, bool> dir in necessaryBorders)
{
if(dir.Value)
{
if(!area.AreaExits.Contains(dir.Key)) areaUseful = false;
}
if(!dir.Value)
{
if(area.AreaExits.Contains(dir.Key)) areaUseful = false;
}
if(!areaUseful) break;
}
if(areaUseful) sourceAreas.Add(area);
}
if(sourceAreas.Count >= 1)
{
// If we have more at least one area that fits the bill, we'll try to use that, so that
// the dungeon feels as connected and continuous as possible.
template = sourceAreas[rnd.Next(sourceAreas.Count)];
toAdd.TemplateAreaId = template.AreaId;
toAdd.DungeonName = name;
toAdd.AreaExits.AddRange(template.AreaExits);
toAdd.CR = cr;
foreach(KeyValuePair<ExitDirection, RandomDungeonArea> adj in adjacentToBe)
{
toAdd.AdjacentAreas.Add(adj.Key, adj.Value);
switch(adj.Key)
{
case ExitDirection.North:
adj.Value.AdjacentAreas.Add(ExitDirection.South, toAdd);
break;
case ExitDirection.South:
adj.Value.AdjacentAreas.Add(ExitDirection.North, toAdd);
break;
case ExitDirection.East:
adj.Value.AdjacentAreas.Add(ExitDirection.West, toAdd);
break;
case ExitDirection.West:
adj.Value.AdjacentAreas.Add(ExitDirection.East, toAdd);
break;
case ExitDirection.Up:
adj.Value.AdjacentAreas.Add(ExitDirection.Down, toAdd);
break;
case ExitDirection.Down:
adj.Value.AdjacentAreas.Add(ExitDirection.Up, toAdd);
break;
}
}
areasToGenerate -= (toAdd.AreaExits.Count - toAdd.AdjacentAreas.Count);
AreasOfDungeon.Add(toAdd);
areasNeedingAdjacentAreas.Add(toAdd);
}
else
{
// But if no area fits the bill, we loop over each of the exits we're expecting and
// attach the dead end area with the appropriate exit to them.
foreach(KeyValuePair<ExitDirection, RandomDungeonArea> adj in adjacentToBe)
{
int X = toAdd.X;
int Y = toAdd.Y;
int Z = toAdd.Z;
switch(adj.Key)
{
case ExitDirection.North:
template = getSingleExitArea(ExitDirection.South, areaPrefix);
break;
case ExitDirection.South:
template = getSingleExitArea(ExitDirection.North, areaPrefix);
break;
case ExitDirection.East:
template = getSingleExitArea(ExitDirection.West, areaPrefix);
break;
case ExitDirection.West:
template = getSingleExitArea(ExitDirection.East, areaPrefix);
break;
case ExitDirection.Up:
template = getSingleExitArea(ExitDirection.Down, areaPrefix);
break;
case ExitDirection.Down:
template = getSingleExitArea(ExitDirection.Up, areaPrefix);
break;
}
toAdd = new RandomDungeonArea();
toAdd.X = X;
toAdd.Y = Y;
toAdd.Z = Z;
toAdd.TemplateAreaId = template.AreaId;
toAdd.DungeonName = name;
toAdd.AreaExits.AddRange(template.AreaExits);
toAdd.AdjacentAreas.Add(adj.Key, adj.Value);
switch(adj.Key)
{
case ExitDirection.North:
adj.Value.AdjacentAreas.Add(ExitDirection.South, toAdd);
break;
case ExitDirection.South:
adj.Value.AdjacentAreas.Add(ExitDirection.North, toAdd);
break;
case ExitDirection.East:
adj.Value.AdjacentAreas.Add(ExitDirection.West, toAdd);
break;
case ExitDirection.West:
adj.Value.AdjacentAreas.Add(ExitDirection.East, toAdd);
break;
case ExitDirection.Up:
adj.Value.AdjacentAreas.Add(ExitDirection.Down, toAdd);
break;
case ExitDirection.Down:
adj.Value.AdjacentAreas.Add(ExitDirection.Up, toAdd);
break;
}
areasToGenerate -= (toAdd.AreaExits.Count - toAdd.AdjacentAreas.Count);
AreasOfDungeon.Add(toAdd);
areasNeedingAdjacentAreas.Add(toAdd);
}
}
}
}