public virtual void RegisterInGrid(ArchivedSegment what, SegmentStump where) { foreach (SegmentCell cell in what.Occupation[where.ZeroPosRot.Facing]) { PlanningGrid[where.ZeroPosRot.U + cell.U, where.ZeroPosRot.R + cell.R] = GridOccupation.BlockedByCell; } foreach (SegmentCellOriented opening in what.Openings[where.ZeroPosRot.Facing]) { PlanningGrid[where.ZeroPosRot.U + opening.U, where.ZeroPosRot.R + opening.R] = GridOccupation.BlockedByOpening; } }
public static ArchivedSegment GetRandomSegment(int category, int theme, int doorType) { //Debug.Log("getting segment cat theme: " + category + " " + theme); if (category == SegmentCategory.Entrance) { return(Categoried [category, theme] [Random.Range(0, Categoried [category, theme].Count)]); } //if an entrance is needed, then pass random one. Otherwise try matching doors do { Result = Categoried [category, theme] [Random.Range(0, Categoried [category, theme].Count)]; }while((Result.DoorsCombined & DoorType.GetCompatMaskForDoorType(doorType)) == 0); //at least one door in segment must be compatible with door exiting previous segment return(Result); }
public int PathWeight; //cells generated so far as branch from main path or cells generated so far as main path if part of it public void PlanFromScheme(ArchivedSegment scheme, SegmentStump gridStump) { Scheme = scheme; ZeroPosRot = new SegmentCellOriented(gridStump.ZeroPosRot.U, gridStump.ZeroPosRot.R, gridStump.ZeroPosRot.Facing, gridStump.ZeroPosRot.Type, gridStump.ZeroPosRot.Altitude); SegmentRole = gridStump.StumpRole; PathDepth = gridStump.PathDepth + 1; PathWeight = gridStump.PathWeight + Scheme.Weight; this.HasParent(gridStump.Parent); if (gridStump.Parent != null) { gridStump.Parent.IsParentOf(this); } }
public virtual bool CanItFit(ArchivedSegment what, SegmentStump whereTo) { int gridU, gridR; foreach (SegmentCell cell in what.Occupation[whereTo.ZeroPosRot.Facing]) //main cells intersection check { gridU = whereTo.ZeroPosRot.U + cell.U; gridR = whereTo.ZeroPosRot.R + cell.R; if ((gridU < 0) || (gridU > Settings.PlanGridDimensions) || (gridR < 0) || (gridR > Settings.PlanGridDimensions)) { return(false); } if ((cell.U == 0) && (cell.R == 0)) //is it an entrance cell { if (PlanningGrid[gridU, gridR] == GridOccupation.BlockedByCell) //entrance can be planned on top of openings(that's the point) { return(false); } } else { if (PlanningGrid[gridU, gridR] != GridOccupation.Empty) //not-entrance can be planned only on empty space { return(false); } } } foreach (SegmentCellOriented opening in what.Openings[whereTo.ZeroPosRot.Facing]) //openings intersection check { gridU = whereTo.ZeroPosRot.U + opening.U; gridR = whereTo.ZeroPosRot.R + opening.R; if ((gridU < 0) || (gridU > Settings.PlanGridDimensions) || (gridR < 0) || (gridR > Settings.PlanGridDimensions)) { return(false); } if (PlanningGrid[gridU, gridR] != GridOccupation.Empty) //opening for future segment needs at least 1 cell of open space { return(false); } } return(true); }
public void FillRotations(ArchivedSegment segment) // fill in the 90 180 270 rotated variants of segment { //Pivot position and rotation (matters when segment is an ED variant and prefab pivot is displaced and has it's own rotation) segment.PivotCell[SegmentRotation.Right] = new SegmentCellOriented(-segment.PivotCell[SegmentRotation.Up].R, segment.PivotCell[SegmentRotation.Up].U, (segment.PivotCell[SegmentRotation.Up].Facing + 1) % 4, 0, segment.PivotCell[SegmentRotation.Up].Altitude); segment.PivotCell[SegmentRotation.Down] = new SegmentCellOriented(-segment.PivotCell[SegmentRotation.Up].U, -segment.PivotCell[SegmentRotation.Up].R, (segment.PivotCell[SegmentRotation.Up].Facing + 2) % 4, 0, segment.PivotCell[SegmentRotation.Up].Altitude); segment.PivotCell[SegmentRotation.Left] = new SegmentCellOriented(segment.PivotCell[SegmentRotation.Up].R, -segment.PivotCell[SegmentRotation.Up].U, (segment.PivotCell[SegmentRotation.Up].Facing + 3) % 4, 0, segment.PivotCell[SegmentRotation.Up].Altitude); segment.Occupation[SegmentRotation.Right] = new List <SegmentCell>(); segment.Occupation[SegmentRotation.Down] = new List <SegmentCell>(); segment.Occupation[SegmentRotation.Left] = new List <SegmentCell>(); foreach (SegmentCell cell in segment.Occupation[SegmentRotation.Up]) { segment.Occupation[SegmentRotation.Right].Add(new SegmentCell(-cell.R, cell.U)); segment.Occupation[SegmentRotation.Down].Add(new SegmentCell(-cell.U, -cell.R)); segment.Occupation[SegmentRotation.Left].Add(new SegmentCell(cell.R, -cell.U)); } segment.Openings[SegmentRotation.Right] = new List <SegmentCellOriented>(); segment.Openings[SegmentRotation.Down] = new List <SegmentCellOriented>(); segment.Openings[SegmentRotation.Left] = new List <SegmentCellOriented>(); foreach (SegmentCellOriented opening in segment.Openings[SegmentRotation.Up]) { segment.Openings[SegmentRotation.Right].Add(new SegmentCellOriented(-opening.R, opening.U, (opening.Facing + 1) % 4, opening.Type, opening.Altitude)); segment.Openings[SegmentRotation.Down].Add(new SegmentCellOriented(-opening.U, -opening.R, (opening.Facing + 2) % 4, opening.Type, opening.Altitude)); segment.Openings[SegmentRotation.Left].Add(new SegmentCellOriented(opening.R, -opening.U, (opening.Facing + 3) % 4, opening.Type, opening.Altitude)); } }
//private int SideBranchingEntropy = 0; //influences chances of sideways branching; rises as branches fail to branch when they should (dungeon topology wont allow it) //WIP public override bool GeneratePlan(out DungeonPlan dungeonPlan) { dungeonPlan = new DungeonPlan(); SegmentStump MainPathStump; List <SegmentStump> SidewayStumps = new List <SegmentStump>(); if (PlanningGrid == null) { PlanningGrid = new byte[Settings.PlanGridDimensions + 1, Settings.PlanGridDimensions + 1]; } else { Array.Clear(PlanningGrid, 0, PlanningGrid.Length); } //ENTRANCE PlannedSegment EntrancePlan = new PlannedSegment(); SegmentStump EntranceStump = new SegmentStump(null, new SegmentCellOriented((int)(Settings.PlanGridDimensions * EntranceMargin.x), (int)(Settings.PlanGridDimensions * EntranceMargin.y), SegmentRotation.Up, DoorType.NonExistant, //no door into first segment 0), //starting altitude is considered zero DungeonSegmentRole.MainPath, //Entrance is a start of main path 0, //dungeon starting segment has 0 depth and weight before it 0); ArchivedSegment schemeChoice = TryFindFittingSegment(SegmentCategory.Entrance, EntranceStump); if (schemeChoice == null) { Debug.Log("Could not plan entrance"); return(false); } else { RegisterInGrid(schemeChoice, EntranceStump); } EntrancePlan.PlanFromScheme(schemeChoice, EntranceStump); dungeonPlan.AddSegment(EntrancePlan); List <SegmentStump> OpeningsStumps = SegmentStump.MakeStumpsForOpenings(EntrancePlan); ShuffleList <SegmentStump>(OpeningsStumps); MainPathStump = OpeningsStumps[0]; //first one after shuffle is main, the rest are sideways MainPathStump.StumpRole = DungeonSegmentRole.MainPath; OpeningsStumps.RemoveAt(0); foreach (SegmentStump stump in OpeningsStumps) { stump.StumpRole = DungeonSegmentRole.Sideway; stump.PathDepth = 0; //depth and weight are related to sideway now stump.PathWeight = 0; SidewayStumps.Add(stump); } //MAIN PATH PlannedSegment MainPathPlan; int ChosenCategory; while ((ChosenCategory = ChooseCategoryForStump(MainPathStump)) != SegmentCategory.Exit) { MainPathPlan = new PlannedSegment(); schemeChoice = TryFindFittingSegment(ChosenCategory, MainPathStump); if (schemeChoice == null) { //Debug.Log("Could not plan part of main path at Depth / Weight: " + MainPathStump.PathDepth + " / " + MainPathStump.PathWeight); return(false); } else { RegisterInGrid(schemeChoice, MainPathStump); } MainPathPlan.PlanFromScheme(schemeChoice, MainPathStump); dungeonPlan.AddSegment(MainPathPlan); OpeningsStumps = SegmentStump.MakeStumpsForOpenings(MainPathPlan); ShuffleList <SegmentStump>(OpeningsStumps); MainPathStump = OpeningsStumps[0]; //first one after shuffle is main, the rest are sideways MainPathStump.StumpRole = DungeonSegmentRole.MainPath; OpeningsStumps.RemoveAt(0); foreach (SegmentStump stump in OpeningsStumps) { stump.StumpRole = DungeonSegmentRole.Sideway; stump.PathDepth = 0; stump.PathWeight = 0; SidewayStumps.Add(stump); } } //EXIT PlannedSegment MainPathExitPlan = new PlannedSegment(); schemeChoice = TryFindFittingSegment(SegmentCategory.Exit, MainPathStump); if (schemeChoice == null) { //Debug.Log("Could not plan exit part of main path"); return(false); } else { RegisterInGrid(schemeChoice, MainPathStump); } MainPathExitPlan.PlanFromScheme(schemeChoice, MainPathStump); dungeonPlan.AddSegment(MainPathExitPlan); //SIDEWAYS PlannedSegment SidewayPlan; while (SidewayStumps.Count != 0) { ChosenCategory = ChooseCategoryForStump(SidewayStumps[0]); SidewayPlan = new PlannedSegment(); schemeChoice = TryFindFittingSegment(ChosenCategory, SidewayStumps[0]); if (schemeChoice == null) { //Debug.Log("Could not plan a sideway"); return(false); } else { RegisterInGrid(schemeChoice, SidewayStumps[0]); } SidewayPlan.PlanFromScheme(schemeChoice, SidewayStumps[0]); dungeonPlan.AddSegment(SidewayPlan); OpeningsStumps = SegmentStump.MakeStumpsForOpenings(SidewayPlan); //if sideway continues - add its exit stumps to the end of SidewayStumps foreach (SegmentStump stump in OpeningsStumps) { stump.StumpRole = DungeonSegmentRole.Sideway; SidewayStumps.Add(stump); } SidewayStumps.RemoveAt(0); //stump is built upon and should be removed } return(true); //generated successfully }
public void Variate() //make entrance-displaced variants and fill in their rotations { if ((Openings[SegmentRotation.Up].Count != 0) && (Category != SegmentCategory.Entrance)) //entrance can not have alternative way to enter in it { List <SegmentCell> NewOccupation; List <SegmentCellOriented> NewOpenings; int NeededSegmentRotation = 0; int UCorrection = 0; int RCorrection = 0; foreach (SegmentCellOriented opening in Openings[SegmentRotation.Up]) { NewOccupation = new List <SegmentCell>(); NewOpenings = new List <SegmentCellOriented>(); switch (opening.Facing) { case CellFacing.Up: NeededSegmentRotation = SegmentRotation.Down; //rotation of the original that will be a default(up) rotation for variant UCorrection = opening.U - 1; //movement of the segment after rotation that is needed for the cell with opening(new entrance) to be at local 0.0 RCorrection = opening.R; break; case CellFacing.Right: NeededSegmentRotation = SegmentRotation.Right; UCorrection = opening.R - 1; RCorrection = -opening.U; break; case CellFacing.Down: NeededSegmentRotation = SegmentRotation.Up; UCorrection = -opening.U - 1; RCorrection = -opening.R; break; case CellFacing.Left: NeededSegmentRotation = SegmentRotation.Left; UCorrection = -opening.R - 1; RCorrection = opening.U; break; } foreach (SegmentCell rotcell in Occupation[NeededSegmentRotation]) { NewOccupation.Add(new SegmentCell(rotcell.U + UCorrection, rotcell.R + RCorrection)); } foreach (SegmentCellOriented rotopening in Openings[NeededSegmentRotation]) { if ((rotopening.U + UCorrection == -1) && (rotopening.R + RCorrection == 0) && (rotopening.Facing == CellFacing.Down)) //check and skip if exit with current opening is the new entrance { continue; } NewOpenings.Add(new SegmentCellOriented(rotopening.U + UCorrection, rotopening.R + RCorrection, rotopening.Facing, rotopening.Type, rotopening.Altitude - opening.Altitude)); } int OldEntranceOpeningU = 0; //Old entrance should be listed as viable opening now int OldEntranceOpeningR = 0; int OldEntranceOpeningFacing = 0; switch (NeededSegmentRotation) { case SegmentRotation.Up: OldEntranceOpeningU = UCorrection - 1; OldEntranceOpeningR = RCorrection; OldEntranceOpeningFacing = CellFacing.Down; break; case SegmentRotation.Right: OldEntranceOpeningU = UCorrection; OldEntranceOpeningR = RCorrection - 1; OldEntranceOpeningFacing = CellFacing.Left; break; case SegmentRotation.Down: OldEntranceOpeningU = UCorrection + 1; OldEntranceOpeningR = RCorrection; OldEntranceOpeningFacing = CellFacing.Up; break; case SegmentRotation.Left: OldEntranceOpeningU = UCorrection; OldEntranceOpeningR = RCorrection + 1; OldEntranceOpeningFacing = CellFacing.Right; break; } NewOpenings.Add(new SegmentCellOriented(OldEntranceOpeningU, OldEntranceOpeningR, OldEntranceOpeningFacing, EntranceDoorType, -opening.Altitude)); //add an old entrance as possible exit with opening ArchivedSegment Variant = new ArchivedSegment(NewOccupation, NewOpenings, opening.Type, Theme, Category, PrefabName, Chance, false); //pivot of the prefab is displaced and has added rotation Variant.PivotCell[SegmentRotation.Up] = new SegmentCellOriented(UCorrection, RCorrection, NeededSegmentRotation, DoorType.NonExistant, -opening.Altitude); FillRotations(Variant); EDVariants.Add(Variant); } } }