public abstract int ChooseCategoryForStump(SegmentStump stump);  //chooses category of future segment from this stump based on weight and chances in settings


    public virtual ArchivedSegment TryFindFittingSegment(int category, SegmentStump whereTo)
    {
        int                    FailCounter = 0;
        bool                   FitCheck, DoorCheck;
        ArchivedSegment        choice;
        List <ArchivedSegment> Variants = new List <ArchivedSegment>();

        while (FailCounter < SegmentRetriesAllowed)
        {
            Variants.Clear();
            choice = SegmentCodex.GetRandomSegment(category, Settings.DungeonTheme, whereTo.ZeroPosRot.Type);
            Variants.Add(choice);
            if ((choice.EDVariants != null))
            {
                Variants.AddRange(choice.EDVariants);   // segment and all its entrance-displaced variants
            }
            ShuffleList <ArchivedSegment>(Variants);

            foreach (ArchivedSegment variant in Variants)
            {
                DoorCheck = (whereTo.ZeroPosRot.Type == DoorType.NonExistant || DoorType.AreTheeseDoorsCompatible(variant.EntranceDoorType, whereTo.ZeroPosRot.Type));
                if (DoorCheck)
                {
                    FitCheck = CanItFit(variant, whereTo);
                    if (FitCheck)
                    {
                        return(variant);
                    }
                }
            }
            FailCounter++;
        }
        return(null);
    }
 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 override int ChooseCategoryForStump(SegmentStump stump)  //chooses category of future segment from this stump based on role, weight and chances in settings
    {
        int  ExcessiveWeight;
        int  ChanceToClose;
        bool Closing;
        bool Branching;

        switch (stump.StumpRole)
        {
        case DungeonSegmentRole.MainPath:       //main path
            ExcessiveWeight = stump.PathWeight - Settings.MainPathWeightThreshold;
            ChanceToClose   = ExcessiveWeight * Settings.MainClosingChancePerExW;
            Closing         = (ChanceToClose > 0) && (RandomZeroToInc(100) < ChanceToClose);
            Branching       = RandomZeroToInc(100) < Settings.MainPathBranchingChance;
            if (Closing)
            {
                return(SegmentCategory.Exit);       //main closing is dungeon exit
            }
            else
            {
                if (Branching)
                {
                    return(SegmentCategory.Branch);  //main path is branching
                }
                return(SegmentCategory.Corridor);    // if not then a main corridor
            }

        //break;
        default:        //some kind of secondary branching
            ExcessiveWeight = stump.PathWeight - Settings.SidewaysWeightThreshold;
            ChanceToClose   = ExcessiveWeight * Settings.SidewaysClosingChancePerExW;
            Closing         = (ChanceToClose > 0) && (RandomZeroToInc(100) < ChanceToClose);
            Branching       = RandomZeroToInc(100) < Settings.SidewaysBranchingChance;
            if (Closing)
            {
                return(SegmentCategory.Deadend);       //branch closing is plain deadend
            }
            else
            {
                if (Branching)
                {
                    return(SegmentCategory.Branch);  //branch is branching further
                }
                return(SegmentCategory.Corridor);    // if not then a branch corridor
            }
            //break;
        }
    }
    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);
    }
Esempio n. 6
0
    public static List <SegmentStump> MakeStumpsForOpenings(PlannedSegment segment)
    {
        List <SegmentStump> result = new List <SegmentStump>();
        SegmentStump        stump;

        foreach (SegmentCellOriented opening in segment.Scheme.Openings[segment.ZeroPosRot.Facing])
        {
            stump = new SegmentStump(segment,
                                     new SegmentCellOriented(segment.ZeroPosRot.U + opening.U,
                                                             segment.ZeroPosRot.R + opening.R,
                                                             opening.Facing,
                                                             opening.Type,
                                                             segment.ZeroPosRot.Altitude + opening.Altitude),
                                     segment.SegmentRole,
                                     segment.PathDepth,
                                     segment.PathWeight);
            result.Add(stump);
        }
        return(result);
    }
    //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
    }
 //Building helper methods
 public abstract int ChooseCategoryForStump(SegmentStump stump);  //chooses category of future segment from this stump based on weight and chances in settings