Пример #1
0
    private void GenerateRiver(Vec2i start)
    {
        Vec2i end = null;

        for (int i = 1; i < 100; i++)
        {
            if (end != null)
            {
                break;
            }
            for (int j = 0; j < DIRS.Length; j++)
            {
                Vec2i pos = start + DIRS[j] * i;
                if (GameGenerator2.InBounds(pos))
                {
                    if (GameGen.TerGen.ChunkBases[pos.x, pos.z].Biome == ChunkBiome.ocean)
                    {
                        end = pos;
                        break;
                    }
                }
            }
        }
        if (end == null)
        {
            return;
        }



        LineI li = new LineI(start, end);


        List <Vec2i> basic = li.ConnectPoints();

        float val1 = GenRan.Random(0.1f, 0.001f);
        float val2 = GenRan.Random(0.1f, 0.001f);
        int   val3 = GenRan.RandomInt(8, 32);
        int   val4 = GenRan.RandomInt(8, 32);

        for (int i = 0; i < basic.Count; i++)
        {
            basic[i] += new Vec2i((int)(val3 * Mathf.Sin(i * val1)), (int)(val4 * Mathf.Sin(i * val2)));
        }
        for (int i = 0; i < basic.Count - 1; i++)
        {
            Vec2i v1 = basic[i];
            Vec2i v2 = basic[i + 1];
            LineI i2 = new LineI(v1, v2);
            foreach (Vec2i v in i2.ConnectPoints())
            {
                GameGen.TerGen.ChunkBases[v.x, v.z].SetChunkFeature(new ChunkRiverNode(v));
            }
        }
        return;
    }
    /// <summary>
    /// Defines the bounds of the building to have an L shape.
    ///
    /// </summary>
    /// <param name="genRan">RNG used to generate building</param>
    /// <param name="smith">Building shell to define wall of</param>
    private static void ChooseLShapedWall(GenerationRandom genRan, Blacksmith smith)
    {
        //Define a base rectangular wall
        List <Vec2i> wallPoints = new List <Vec2i>();

        wallPoints.Add(new Vec2i(0, 0));
        wallPoints.Add(new Vec2i(smith.Width - 1, 0));
        wallPoints.Add(new Vec2i(smith.Width - 1, smith.Height - 1));
        wallPoints.Add(new Vec2i(0, smith.Height - 1));



        //Choose which point index we wish to move
        int deltaPointI = genRan.RandomInt(0, wallPoints.Count);
        //We find which direction and amount the point has to move to not leave the bounds
        int   xDir     = (wallPoints[deltaPointI].x == 0 ? 1 : -1) * genRan.RandomInt(smith.Width / 3, smith.Width - smith.Width / 3);
        int   zDir     = (wallPoints[deltaPointI].z == 0 ? 1 : -1) * genRan.RandomInt(smith.Height / 3, smith.Height - smith.Height / 3);
        Vec2i newPoint = new Vec2i(xDir, zDir) + wallPoints[deltaPointI];

        //wallPoints.Insert(deltaPointI-1, newPoint);
        //We find the direction from the previous corner to this one,
        //we use this to translate the point accordingly
        Vec2i nm1_to_n = wallPoints[deltaPointI] - wallPoints[(deltaPointI - 1 + wallPoints.Count) % wallPoints.Count];
        Vec2i np1_to_n = wallPoints[(deltaPointI + 1) % wallPoints.Count] - wallPoints[deltaPointI];

        if (nm1_to_n.x == 0)
        {
            wallPoints[deltaPointI].z = newPoint.z;
        }
        else
        {
            wallPoints[deltaPointI].x = newPoint.x;
        }

        // Vec2i np1_to_n = wallPoints[(deltaPointI + 1) % wallPoints.Count] - wallPoints[deltaPointI];

        Vec2i newPoint2 = new Vec2i(newPoint.x, newPoint.z);

        if (np1_to_n.x == 0)
        {
            newPoint2.x = wallPoints[(deltaPointI + 1) % wallPoints.Count].x;
        }
        else
        {
            newPoint2.z = wallPoints[(deltaPointI + 1) % wallPoints.Count].z;
        }
        wallPoints.Insert((deltaPointI + 1), newPoint);
        wallPoints.Insert((deltaPointI + 2), newPoint2);

        smith.BoundingWall = wallPoints.ToArray();
    }
Пример #3
0
    /// <summary>
    /// Places a roof over the specified building.
    /// The roof will only cover the tile specified by 'roofTileID'. If this is null,
    /// then a roof over the total building will be created
    /// </summary>
    /// <param name="vox"></param>
    /// <param name="build"></param>
    /// <param name="roofTileID"></param>
    public static void AddRoof(GenerationRandom genRan, BuildingVoxels vox, Building build, Voxel roofVox, int roofStartY = 5, Tile roofTileReplace = null)
    {
        if (roofTileReplace == null)
        {
            Vec2i dir = genRan.RandomQuadDirection();
            dir.x = Mathf.Abs(dir.x);
            dir.z = Mathf.Abs(dir.z);

            Vec2i start   = new Vec2i(build.Width / 2 * dir.x, build.Height / 2 * dir.z);
            Vec2i end     = start + new Vec2i(dir.z * build.Width, dir.x * build.Height);
            LineI t       = new LineI(start, end);
            float maxDist = Mathf.Max(t.Distance(new Vec2i(0, 0)), t.Distance(new Vec2i(build.Width - 1, 0)),
                                      t.Distance(new Vec2i(0, build.Height - 1)), t.Distance(new Vec2i(build.Width - 1, build.Height - 1)));

            int   maxHeight = genRan.RandomInt(4, 6);
            float scale     = maxHeight / (maxDist + 1);
            //float scale = 0.7f;

            for (int x = 0; x < build.Width; x++)
            {
                for (int z = 0; z < build.Height; z++)
                {
                    int height = (int)Mathf.Clamp((maxDist - t.Distance(new Vec2i(x, z)) + 1) * scale, 1, World.ChunkHeight - 1);
                    for (int y = 0; y < height; y++)
                    {
                        vox.AddVoxel(x, Mathf.Clamp(roofStartY + y, 0, World.ChunkHeight - 1), z, roofVox);
                    }
                }
            }
        }
    }
Пример #4
0
    public override WorldObject CreateWorldObject(Transform transform = null)
    {
        GenerationRandom genRan = new GenerationRandom(WorldPosition.GetHashCode() * 13);
        int count = genRan.RandomInt(2, 5);

        WorldObject r1 = null;

        for (int i = 0; i < count; i++)
        {
            Vector3 pos   = genRan.RandomVector3(-MaxSize, MaxSize, (i) * 0.1f, (i) * 0.2f + 0.1f, -MaxSize, MaxSize) / 100f;
            float   rSize = genRan.Random(0.5f, 1.5f);
            Rock    r     = new Rock(WorldPosition, pos, rSize);

            if (i == 0)
            {
                r1 = r.CreateWorldObject(transform);
            }
            else
            {
                WorldObject rn = r.CreateWorldObject(r1.transform);
                rn.transform.localPosition = pos;
            }
        }
        return(r1);
    }
Пример #5
0
    /// <summary>
    /// Generates a quest with the goal of clearing a specific chunk structure
    /// </summary>
    /// <param name="dungeonPos"></param>
    /// <param name="chunkStructure"></param>
    /// <returns></returns>
    private Quest GenerateDungeonQuest(Vec2i dungeonPos, ChunkStructure chunkStructure)
    {
        questCount++;
        //Get the dungeon this quest is based on
        Dungeon dun = chunkStructure.DungeonEntrance.GetDungeon();
        //If the dungeon doesn't have a key (generation should be set so it doesn't), we create one
        Key key = dun.GetKey();

        if (key == null)
        {
            key = new SimpleDungeonKey(GenRan.RandomInt(1, int.MaxValue));
            dun.SetKey(key);
        }

        //We build the quest in reverse, we first define the goal
        List <QuestTask> revTasks = new List <QuestTask>();

        //For a dungeon quest, this is always to kill the dungeon boss
        revTasks.Add(new QuestTask("Kill " + dun.Boss.Name, QuestTask.QuestTaskType.KILL_ENTITY, new object[] { dun.Boss }));

        //The second to last task is to get to the dungeon,
        revTasks.Add(new QuestTask("Get to dungeon", QuestTask.QuestTaskType.GO_TO_LOCATION, new object[] { chunkStructure.WorldMapLocation, dun.WorldEntrance }));

        //Before we get to the dungeon, we need to get the key.
        //The key can either be held by an entity, or it can be found in a
        //random chunk structure with no dungeon.


        return(GenerateDungeonKeyQuest_RandomStructure(dungeonPos, dun, revTasks));
    }
Пример #6
0
    /// <summary>
    /// Generates the simplest type of house - a shack
    /// A shack is made of either (cobble?) stone or wood,
    /// it consists of only 1 room, with basic objects inside (bed, chair, table)
    /// </summary>
    /// <param name="house"></param>
    /// <param name="vox"></param>
    /// <returns></returns>
    public static House GenerateShack(GenerationRandom genRan, House house, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        vox           = new BuildingVoxels(house.Width, World.ChunkHeight, house.Height);
        Tile[,] floor = new Tile[house.Width, house.Height];

        BuildingGenerator.BuildBoundingWallRect(vox, house.Width, house.Height, 6, Voxel.wood);
        //BuildingGenerator.ConnectBoundingWall(vox, house.BoundingWall, Voxel.wood, 5);
        BuildingGenerator.SetTiles(floor, 0, 0, house.Width - 1, house.Height - 1, Tile.STONE_FLOOR);
        house.SetBuilding(floor);

        BuildingGenerator.ChooseEntrancePoint(genRan, vox, house, plan);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: true);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: true);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false);
        house.InsideWallPoints = BuildingGenerator.FindInsideWallBoundryPoints(vox, house);

        /*foreach (Vec2i v in house.InsideWallPoints)
         * {
         *  //house.AddObjectReference(new Chest().SetPosition(v));
         *  WorldObjectData bed = new Bed().SetPosition(v);
         *  bed.SetRotation(Vec2i.Angle(Vec2i.Forward, BuildingGenerator.GetWallPointDirection(house, v)));
         *  if(!house.ObjectIntersects(bed))
         *      house.AddObjectReference(bed);
         * }*/

        BuildingGenerator.PlaceObjectAgainstWall(genRan, new DoubleBed(), 0, vox, house, .3f, distToEntr: 4, attemptsCount: 40);
        BuildingGenerator.PlaceObjectAgainstWall(genRan, new Chest(), 0, vox, house, 0.1f, distToEntr: 3, attemptsCount: 40);

        for (int i = 0; i < house.BoundingWall.Length; i++)
        {
            BuildingGenerator.PlaceObjectAgainstWall(genRan, new WallTorch(), 1.5f, vox, house, 0f, requireWallBacking: true);
        }
        house.AddExternalObject(new BuildingInternalNoWalkFloor(new Vector3(1, 0, 1), new Vector3(house.Width - 2, 5, house.Height - 2)));
        BuildingGenerator.AddRoof(genRan, vox, house, Voxel.thatch);

        BuildingSubworldBuilder b = new BuildingSubworldBuilder(house, vox, plan);

        b.CreateSubworld();
        //ChunkData[,] subChunks = new ChunkData[1, 1];


        return(house);
    }
Пример #7
0
    /// <summary>
    /// We override the create world object function for a tree. This is done as we need to load in multiple
    /// parts of the tree
    /// </summary>
    /// <param name="transform"></param>
    /// <returns></returns>
    public override WorldObject CreateWorldObject(Transform transform = null)
    {
        //Create random with seed unique to tree position - this ensures tree should be same every time.
        GenerationRandom genRan = new GenerationRandom(WorldPosition.x * World.WorldSize * World.ChunkSize + WorldPosition.z);
        int   canopy            = genRan.RandomInt(3, 7);
        float angleOffset       = genRan.Random(0, Mathf.PI);

        float       range    = Mathf.Sqrt(canopy * 0.5f) * 0.8f;
        WorldObject treeBase = WorldObject.CreateWorldObject(this, transform);
        Vec2i       zero     = new Vec2i(0, 0);

        Vector3[] canopyPositions = new Vector3[canopy];

        for (int i = 0; i < canopy; i++)
        {
            //Define the positions of each canopy as roughly circular about the middle of the tree.
            float   angle  = (Mathf.PI * 2 / (canopy)) * i + angleOffset;
            Vector2 delta  = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * range + genRan.RandomVector2(-0.1f, 0.1f);
            float   height = 1.8f + genRan.Random(0, 1f);
            //Store the total position for use later, then generate the canopy itself.
            canopyPositions[i] = new Vector3(delta.x, height, delta.y);
            TreeCanopy tr = new TreeCanopy(zero, canopyPositions[i]);
            tr.SetRandom(genRan);
            tr.CreateWorldObject(treeBase.transform);
        }
        //Generate the trunk

        float      trunkHeight = 1.2f;
        float      trunkScale  = 1.2f;
        TreeBranch trunk       = new TreeBranch(zero);

        trunk.SetCharacteristic(Vector3.zero, new Vector3(0, 0, 0), new Vector3(1, trunkScale, 1));
        WorldObject trunkObj = trunk.CreateWorldObject(treeBase.transform);
        //MeshCollider mc  =trunkObj.gameObject.AddComponent<MeshCollider>();
        //mc.sharedMesh = trunkObj.gameObject.GetComponent<MeshFilter>().mesh;
        Vector3 trunkTop = Vector3.up * trunkHeight * trunkScale; //Scale to correct height

        foreach (Vector3 v in canopyPositions)
        {
            TreeBranch canopyBranch = new TreeBranch(zero);
            //Calculate the Euler angles from the branch base to the canopy
            Vector3 delta_pos = v - trunkTop;
            Quaternion.FromToRotation(Vector3.up, delta_pos);
            //Vector3 rot = Quaternion.FromToRotation(trunkTop, v*5f).eulerAngles;
            Vector3 rot   = Quaternion.FromToRotation(Vector3.up, delta_pos).eulerAngles;
            float   scale = Vector3.Distance(v, trunkTop) / trunkHeight;
            canopyBranch.SetCharacteristic(trunkTop, rot, new Vector3(1 / scale, scale, 1 / scale));
            canopyBranch.CreateWorldObject(treeBase.transform);
        }

        return(treeBase);
    }
Пример #8
0
    public static Building CreateBuilding(GenerationRandom genRan, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        Vec2i zero      = new Vec2i(0, 0);
        int   maxWidth  = (plan.DesiredSize == null || plan.DesiredSize == zero) ?Mathf.Min(plan.BuildingPlan.MaxSize, plan.MaxWidth): plan.DesiredSize.x;
        int   maxHeight = (plan.DesiredSize == null || plan.DesiredSize == zero)? Mathf.Min(plan.BuildingPlan.MaxSize, plan.MaxHeight) : plan.DesiredSize.z;
        int   width     = genRan.RandomInt(plan.BuildingPlan.MinSize, maxWidth);
        int   height    = genRan.RandomInt(plan.BuildingPlan.MinSize, maxHeight);

        if (plan.BuildingPlan == Building.BLACKSMITH)
        {
            Blacksmith smith = BlacksmithGenerator.GenerateBlacksmith(genRan, new Blacksmith(width, height), out vox, plan);
            return(smith);
        }
        if (plan.BuildingPlan == Building.BARACKS)
        {
            Barracks barr = BarracksGenerator.GenerateBarracks(genRan, new Barracks(width, height), out vox, plan);
            return(barr);
        }
        if (plan.BuildingPlan == Building.TAVERN)
        {
            return(TavernGenerator.GenerateTavern(genRan, new Tavern(width, height), out vox, plan));
        }
        if (plan.BuildingPlan == Building.VEGFARM)
        {
            Farm farm = FarmGenerator.GenerateVegFarm(genRan, new Farm(width, height), out vox, plan);
            return(farm);
        }
        if (plan.BuildingPlan == Building.WHEATFARM)
        {
            Farm farm = FarmGenerator.GenerateWheatFarm(genRan, new Farm(width, height), out vox, plan);
            return(farm);
        }

        House house = HouseGenerator.GenerateHouse(genRan, new House(width, height), out vox, plan);

        return(house);
        //return GenerateHouse(out vox, width, height);
    }
Пример #9
0
    /// <summary>
    /// Places a small amount of large paths
    /// </summary>
    private void PlaceMainPaths(int initialPathCount = 9)
    {
        //Calculate node map size
        MapNodeSize = TileSize / NodeSize;
        NodeMap     = new bool[MapNodeSize, MapNodeSize];
        BuildingMap = new bool[MapNodeSize, MapNodeSize];
        Path        = new bool[TileSize, TileSize];
        AllNodes    = new List <Vec2i>();

        Vec2i startDir;
        Vec2i entranceToMid = Middle - Entrance;

        //Find the entrance direction
        if (Mathf.Abs(entranceToMid.x) > Mathf.Abs(entranceToMid.z))
        {
            startDir = new Vec2i((int)Mathf.Sign(entranceToMid.x), 0);
        }
        else
        {
            startDir = new Vec2i(0, (int)Mathf.Sign(entranceToMid.z));
        }
        //The start direction for our path
        EntranceSide = startDir;
        //Calculate a random length
        int length = GenerationRandom.RandomInt(Shell.Type.GetSize() / 2 - 1, Shell.Type.GetSize() - 1) * NodeSize;

        Vec2i nodeEntr = Vec2i.FromVector2(new Vector2((float)Entrance.x / NodeSize, (float)Entrance.z / NodeSize)) * NodeSize;

        //Place 'main road'
        AddPath(nodeEntr, startDir, length, 5, NodeMap, AllNodes, NodeSize, true);
        //We generate other initial paths
        for (int i = 0; i < initialPathCount - 1; i++)
        {
            GeneratePathBranch(AllNodes, width: 3);
        }
    }
    /// <summary>
    /// Defines the building shape to be rectangular, with a rectangular section defining outside,
    /// and another defining inside
    /// </summary>
    /// <param name="genRan"></param>
    /// <param name="smith"></param>
    private static void ChooseHalfCutWall(GenerationRandom genRan, Blacksmith smith)
    {
        //Define a base rectangular wall
        List <Vec2i> wallPoints = new List <Vec2i>();

        wallPoints.Add(new Vec2i(0, 0));
        wallPoints.Add(new Vec2i(smith.Width - 1, 0));
        wallPoints.Add(new Vec2i(smith.Width - 1, smith.Height - 1));
        wallPoints.Add(new Vec2i(0, smith.Height - 1));

        int wallIndex = genRan.RandomInt(0, 4);
        int wp1       = (wallIndex + 1) % 4;

        wallPoints[wallIndex].x = (int)(wallPoints[wallIndex].x * 0.5f);
        wallPoints[wallIndex].z = (int)(wallPoints[wallIndex].z * 0.5f);
        wallPoints[wp1].x       = (int)(wallPoints[wp1].x * 0.5f);
        wallPoints[wp1].z       = (int)(wallPoints[wp1].z * 0.5f);

        smith.BoundingWall = wallPoints.ToArray();
    }
Пример #11
0
    /// <summary>
    /// Generates all empty NPCs, defining only their name, and thier homes
    /// </summary>
    /// <param name="set"></param>
    private List <NPC> GenerateNPCShells(Settlement set)
    {
        if (set.Buildings == null)
        {
            return(null);
        }
        List <NPC> settlementNPCs = new List <NPC>(250);

        List <NPC> inThisHouse = new List <NPC>(10);

        //iterate all building, and check if this is a house
        foreach (Building b in set.Buildings)
        {
            if (b is House)
            {
                inThisHouse.Clear();
                //Define the house and get the possible tiles we can spawn the this houses' NPCs on
                House        h = b as House;
                List <Vec2i> spawnableTiles = h.GetSpawnableTiles();

                for (int i = 0; i < h.capacity; i++)
                {
                    //Attempt to find a valid spawn point
                    Vec2i entitySpawn = MiscUtils.RandomFromArray(spawnableTiles, Random.value);
                    if (entitySpawn == null)
                    {
                        Debug.Log("No valid spawn point found for house " + h.ToString(), Debug.ENTITY_GENERATION);
                        continue;
                    }
                    //Create the empty NPC and add it to the settlement
                    NPC npc = new NPC(isFixed: true);
                    npc.SetPosition(entitySpawn);
                    npc.NPCData.SetHome(h);
                    //First two entities should be male and female (husband and wife)
                    //All others are then randomly assigned
                    if (i == 0)
                    {
                        npc.NPCData.SetGender(NPCGender.male);
                    }
                    else if (i == 1)
                    {
                        npc.NPCData.SetGender(NPCGender.female);
                    }
                    else
                    {
                        npc.NPCData.SetGender((NPCGender)GenerationRan.RandomInt(0, 2));
                    }

                    EntityManager.AddFixedEntity(npc);
                    npc.SetName("NPC " + npc.ID);
                    set.AddNPC(npc);
                    settlementNPCs.Add(npc);
                    inThisHouse.Add(npc);
                }
                //If more than 1 person lives in this house, they are family
                if (inThisHouse.Count > 1)
                {
                    //Iterate all pairs of family members in this house
                    for (int i = 0; i < inThisHouse.Count; i++)
                    {
                        for (int j = 0; j < inThisHouse.Count; j++)
                        {
                            if (i == j)
                            {
                                continue;
                            }
                            inThisHouse[i].EntityRelationshipManager.SetRelationshipTag(inThisHouse[j], EntityRelationshipTag.Family);
                            inThisHouse[j].EntityRelationshipManager.SetRelationshipTag(inThisHouse[i], EntityRelationshipTag.Family);
                        }
                    }
                }
            }
        }
        return(settlementNPCs);
    }
Пример #12
0
    public static bool AddWindow(GenerationRandom genRan, BuildingVoxels vox, Building build, int wallIndex = -1, int size = 2, int height = 1, bool autoReattempt = true, int reattemptCount = 3)
    {
        reattemptCount--;
        if (reattemptCount == 0)
        {
            return(false);
        }
        //if default index, we choose one randomly
        if (wallIndex == -1)
        {
            wallIndex = genRan.RandomInt(0, build.BoundingWall.Length);
        }
        int wp1 = (wallIndex + 1) % build.BoundingWall.Length;

        Vec2i dif = build.BoundingWall[wp1] - build.BoundingWall[wallIndex];

        int absX  = Mathf.Abs(dif.x);
        int signX = (int)Mathf.Sign(dif.x);


        int absZ  = Mathf.Abs(dif.z);
        int signZ = (int)Mathf.Sign(dif.z);


        Vec2i dir = new Vec2i(absX == 0?0:signX, absZ == 0 ? 0 : signZ);



        int len = absX + absZ;

        //if the selected wall has a length that is not large enough to house the window,
        if (len < size + 4)
        {
            if (autoReattempt)
            {
                return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
            }
            //Then we do not build a window
            return(false);
        }


        int   dx    = dir.x == 0 ? 0 : genRan.RandomInt(1, absX - size - 2);
        int   dz    = dir.z == 0 ? 0 : genRan.RandomInt(1, absZ - size - 2);
        Vec2i dPos  = dir * (dx + dz);
        Vec2i start = build.BoundingWall[wallIndex];

        Vec2i cur = start + dPos;

        //If the building has an entrance, we iterate all window points
        //to make sure we aren't breaking a door
        if (build.Entrance != null)
        {
            //If we are too close to the door
            if (cur.QuickDistance(build.Entrance) < (size + 1) * (size + 1))
            {
                if (autoReattempt)
                {
                    return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
                }
                return(false);
            }
            else
            {
                for (int i = 0; i < size; i++)
                {
                    cur = start + dPos + (dir * i);
                    if (cur.x > 0 && cur.z > 0 && cur.x < build.Width && cur.z < build.Height)
                    {
                        if (vox.GetVoxel(cur.x, 2, cur.z) == Voxel.glass)
                        {
                            if (autoReattempt)
                            {
                                return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
                            }
                            return(false);
                        }
                    }
                    else
                    {
                        if (autoReattempt)
                        {
                            return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
                        }
                        return(false);
                    }
                }
            }
        }
        cur = start + dPos;

        Vector3 position = (cur - dir).AsVector3() + Vector3.up;
        Vector3 scale    = new Vector3(0.5f, 2, (dir.x + dir.z) * size);
        float   rotation = Mathf.Acos(dir.z) * Mathf.Rad2Deg;

        //GlassWindow window = new GlassWindow(position, scale, rotation);
        //build.AddObjectReference(window);

        for (int i = -1; i <= size; i++)
        {
            cur = start + dPos + dir * i;

            for (int y = 1; y <= 2 + height; y++)
            {
                if (i < 0 || i >= size || y == 1 || y == 2 + height)
                {
                    vox.AddVoxel(cur.x, y, cur.z, Voxel.glass);
                }
                else
                {
                    vox.ClearVoxel(cur.x, y, cur.z);
                    vox.SetVoxel(cur.x, y, cur.z, Voxel.glass);
                }

                //vox.Add(cur.x, y, cur.z, Voxel.none);
            }
        }



        return(true);
    }
Пример #13
0
    private void AddInitPaths()
    {
        int nodeSize = TileSize / NODE_RES;

        int xStart = GenerationRandom.RandomInt(0 + 3, nodeSize - 3);
        int zLen   = nodeSize - GenerationRandom.RandomInt(0, 3); //Ends 0-3 chunks from settlement end



        int zStartWest = GenerationRandom.RandomInt(2, nodeSize - 3);
        int xLenWest   = GenerationRandom.RandomInt(xStart - 2, xStart);

        EntranceNode = new Vec2i(xStart, 0);
        //Add the path nodes along the z direction (start at south -> north)
        for (int z = 0; z < zLen; z++)
        {
            PathNodes[xStart, z] = 100;

            TestNodes2[xStart, z]        = new SettlementPathNode(new Vec2i(xStart * NODE_RES, z * NODE_RES));
            TestNodes2[xStart, z].IsMain = true;
            SetTile(xStart * NODE_RES, z * NODE_RES, Tile.TEST_BLUE);
        }
        ENTR_NODE = TestNodes2[xStart, 0];



        int zStartEast = GenerationRandom.RandomInt(2, nodeSize - 3);
        int xLenEast   = GenerationRandom.RandomInt(nodeSize - xStart - 2, nodeSize - xStart);


        for (int x = 0; x < xLenEast; x++)
        {
            PathNodes[xStart + x, zStartEast] = 100;
        }


        for (int x = 0; x < xLenWest; x++)
        {
            PathNodes[xStart - x, zStartWest] = 100;
        }

        for (int x = 0; x < nodeSize; x++)
        {
            for (int z = 0; z < nodeSize; z++)
            {
                if (PathNodes[x, z] != 0)
                {
                    if (x > 0 && PathNodes[x - 1, z] != 0)
                    {
                        SetTiles((x - 1) * NODE_RES, z * NODE_RES - 2, (x) * NODE_RES, z * NODE_RES + 2, Tile.TEST_BLUE);
                    }
                    if (z > 0 && PathNodes[x, z - 1] != 0)
                    {
                        SetTiles((x) * NODE_RES - 2, (z - 1) * NODE_RES, (x) * NODE_RES + 2, z * NODE_RES, Tile.TEST_BLUE);
                    }
                    if (x < nodeSize - 1 && PathNodes[x + 1, z] != 0)
                    {
                        SetTiles((x) * NODE_RES, z * NODE_RES - 2, (x + 1) * NODE_RES, z * NODE_RES + 2, Tile.TEST_BLUE);
                    }
                    if (z < nodeSize - 1 && PathNodes[x, z + 1] != 0)
                    {
                        SetTiles((x) * NODE_RES - 2, (z) * NODE_RES, (x) * NODE_RES + 2, (z + 1) * NODE_RES, Tile.TEST_BLUE);
                    }
                }
            }
        }
    }
Пример #14
0
    public Vec2i[] ChooseStartChunks(int count, int minSep)
    {
        //The angle between map middle that each capital should approximately
        //be seperated by
        float thetaSep = 360f / count;

        float   thetaOffset = GenRan.Random(0, 90);
        Vector2 middle      = new Vector2(World.WorldSize / 2, World.WorldSize / 2);

        Vec2i[] caps = new Vec2i[count];
        //We iterate each of the kingdom capital positions we wish to calculate
        for (int i = 0; i < count; i++)
        {
            //Theta compared to (1,0) anticlockwise
            float   theta = thetaOffset + thetaSep * i;
            float   dx    = Mathf.Cos(theta * Mathf.Deg2Rad);
            float   dz    = Mathf.Sin(theta * Mathf.Deg2Rad);
            Vector2 delta = new Vector2(dx, dz);
            //We start at middle
            Vector2 current = middle;

            int minLength = 32;
            int maxLength = -1;

            //iterate out
            for (int l = minLength; l < World.WorldSize / 2; l++)
            {
                current = middle + delta * l;
                Vec2i      curChunk = Vec2i.FromVector2(current);
                ChunkBase2 cb       = GameGen.TerGen.ChunkBases[curChunk.x, curChunk.z];
                if (cb.Biome == ChunkBiome.ocean)
                {
                    //When we reach the ocean, we define this as the max distance away
                    maxLength = l - 1;
                    break;
                }
            }
            //Capital is random point between min length, and max length
            Vec2i capPoint = Vec2i.FromVector2(middle + GenRan.RandomInt(minLength, maxLength) * delta);
            caps[i] = capPoint;
        }

        return(caps);



        Vec2i[] dirs = new Vec2i[] { new Vec2i(1, 1), new Vec2i(-1, 1), new Vec2i(-1, -1), new Vec2i(1, -1) };
        Vec2i   mid  = new Vec2i(World.WorldSize / 2, World.WorldSize / 2);

        for (int i = 100; i < 400; i++)
        {
            for (int j = 0; j < dirs.Length; j++)
            {
                if (caps[j] == null)
                {
                    Vec2i      p = mid + dirs[j] * i;
                    ChunkBase2 b = GameGen.TerGen.ChunkBases[p.x, p.z];
                    if (b.Biome == ChunkBiome.ocean)
                    {
                        Vec2i p_ = mid + dirs[j] * (int)(0.75f * i);
                        caps[j] = p_;

                        GridPoint gp = GameGen.GridPlacement.GetNearestPoint(p_);
                    }
                }
            }
        }
        return(caps);

        for (int i = 0; i < count; i++)
        {
            bool validPoint = false;
            while (!validPoint)
            {
                Vec2i     pos = GenRan.RandomVec2i(0, World.WorldSize - 1);
                GridPoint p   = GameGen.GridPlacement.GetNearestPoint(pos);
                if (p != null && p.IsValid)
                {
                    if (i == 0)
                    {
                        caps[0]    = p.ChunkPos;
                        validPoint = true;
                    }
                    else
                    {
                        int minDist = -1;
                        for (int j = 0; j < i; j++)
                        {
                            int sqrDist = p.ChunkPos.QuickDistance(caps[j]);
                            if (minDist == -1 || sqrDist < minDist)
                            {
                                minDist = sqrDist;
                            }
                        }
                        if (minDist < minSep * minSep)
                        {
                            caps[i]    = p.ChunkPos;
                            validPoint = true;
                        }
                    }
                }
            }
            Debug.Log(caps[i]);
        }
        return(caps);
    }
Пример #15
0
    private void FromRiverSource(Vec2i source, Vec2i end, float startHeight = -1, int distSinceFork = 0, bool riverRaySearch = true)
    {
        int i = 0;

        if (startHeight < 0)
        {
            startHeight = ChunkBases[source.x, source.z].Height;
        }

        i = 0;

        Vec2i last    = source;
        Vec2i mainDir = CalcDir(source, end);



        Vec2i current = source + mainDir;
        bool  isDone  = false;

        Vector2 exactCurrent = current.AsVector2();

        List <RiverPoint> river        = new List <RiverPoint>();
        ChunkRiverNode    previousNode = null;

        while (!isDone)
        {
            int distToEnd = end.QuickDistance(current);

            i++;

            /*
             * if(i%16 == 0 && riverRaySearch)
             * {
             *  bool success = false;
             *  //search up to 16 chunks away
             *  for(int j=1; j<16; j++)
             *  {
             *      if (success)
             *          break;
             *      //search all 8 directions
             *      foreach(Vec2i v in Vec2i.OCT_DIRDIR)
             *      {
             *          Vec2i p = current + v * j;
             *
             *          if(ChunkBases[p.x,p.z].Biome == ChunkBiome.ocean || ChunkBases[p.x, p.z].ChunkFeature is ChunkRiverNode)
             *          {
             *              end = p;
             *              success = true;
             *              break;
             *          }
             *      }
             *  }
             * }*/


            // Vector2 currentFlow = FlowField[current.x, current.z];

            float   fx         = PerlinNoise(current.x, current.z, 36) * 2 - 1;
            float   fz         = PerlinNoise(current.x, current.z, 37) * 2 - 1;
            Vector2 noiseFlow  = new Vector2(fx, fz);
            Vector2 flowField  = FlowField[current.x, current.z];
            Vector2 targetFlow = (end - current).AsVector2().normalized;


            float targetFlowMult = distToEnd < 400 ? 4 * Mathf.Exp((400f - distToEnd) / 200f) : 4;

            Vector2 flow = (noiseFlow + targetFlowMult * targetFlow + 3.5f * flowField).normalized;
            exactCurrent += flow;
            current       = Vec2i.FromVector2(exactCurrent);
            int  check   = Mathf.Min(river.Count, 5);
            bool isValid = true;
            for (int j = 0; j < check; j++)
            {
                if (river[river.Count - j - 1].Pos == current)
                {
                    isValid = false;
                }
            }
            if (!isValid)
            {
                current     += mainDir;
                exactCurrent = current.AsVector2();
            }


            if (ChunkBases[current.x, current.z].Biome == ChunkBiome.ocean)
            {
                isDone = true;
            }
            if (ChunkBases[current.x, current.z].ChunkFeature is ChunkRiverNode)
            {
                isDone = true;
                //Shouldn't be null, but lets do a check anyway
                if (previousNode != null)
                {
                    //Get the river node
                    ChunkRiverNode endNode = ChunkBases[current.x, current.z].ChunkFeature as ChunkRiverNode;
                    //Inform river nodes of flow
                    endNode.FlowIn.Add(previousNode);
                    previousNode.FlowOut.Add(endNode);
                    ModifyRiverHeight(endNode);
                }
                if (GenRan.Random() < 0.5f)
                {
                    PlaceLake(current, 8);
                }
            }
            if (current == end)
            {
                isDone = true;
            }
            ChunkRiverNode nextNode = new ChunkRiverNode(current);
            ChunkBases[current.x, current.z].SetChunkFeature(nextNode);
            if (previousNode != null)
            {
                nextNode.FlowIn.Add(previousNode);
                previousNode.FlowOut.Add(nextNode);
            }
            previousNode = nextNode;
            //If this chunk is too high, we modify it and the surrounding area
            if (ChunkBases[current.x, current.z].Height > startHeight)
            {
                ModifyRiverValleyHeight(current, startHeight);
            }
            else if (ChunkBases[current.x, current.z].Height < startHeight)
            {
                startHeight = ChunkBases[current.x, current.z].Height;
            }
            RiverPoint rp = new RiverPoint();
            rp.Pos  = current;
            rp.Flow = flow;

            river.Add(rp);
            if (i > 4096)
            {
                PlaceLake(current, 12);
                return;
            }


            /*
             * distSinceFork++;
             *
             * if(distSinceFork > 256)
             * {
             *
             *  float p = Mathf.Exp(-distSinceFork/200f);
             *  if(p < GenRan.Random())
             *  {
             *
             *      Vec2i delta = GenRan.RandomVec2i(-64, 64);
             *
             *      FromRiverSource(current + delta, current);
             *      distSinceFork = 0;
             *  }
             *
             * }*/
            mainDir = CalcDir(current, end);
        }
        return;

        if (river.Count > 128)
        {
            int forkCount = Mathf.CeilToInt(river.Count / 128f);
            int jump      = (int)(((float)river.Count) / forkCount);
            int index     = GenRan.RandomInt(0, jump);
            for (int j = 0; j < forkCount; j++)
            {
                if (index > river.Count - 30)
                {
                    return;
                }
                RiverPoint rp      = river[index];
                Vec2i      forkEnd = rp.Pos;
                Vec2i      delta   = GenRan.RandomVec2i(-32, 32);

                Vector2 endToForkDir = (forkEnd - end).AsVector2().normalized;

                Vec2i forkStart = Vec2i.FromVector2(forkEnd.AsVector2() + endToForkDir * GenRan.Random(64, 128)) + delta;


                FromRiverSource(forkStart, forkEnd);



                index += jump + GenRan.RandomInt(-32, 32);
            }
        }
    }
Пример #16
0
    /// <summary>
    /// Generates a tunnel of width 1 as a guide to generate the rest of
    /// the dungeon
    /// </summary>
    private void GeneratePath(Vec3i startPosition, int radius = 3)
    {
        //We define the list that stores the tunnel
        List <Vec3i> tunnel = new List <Vec3i>();

        //We initiate it with a start position, and a second position (this helps define the initial direction)
        tunnel.Add(startPosition);
        //The second position is chosen as the direction away from the boundry of the dungeon

        int   xDir           = startPosition.x < TileSize.x / 2 ? 1 : GenRan.RandomInt(-1, 1);
        int   zDir           = xDir == 0 ? (startPosition.z < TileSize.x / 2 ? 1 : -1) : GenRan.RandomInt(-1, 2);
        Vec3i startDirection = new Vec3i(xDir, 0, zDir);

        tunnel.Add(startPosition + startDirection);

        startPosition = startPosition + startDirection;


        for (int i = 0; i < 100; i++)
        {
            startPosition = ChooseNextPosition(tunnel, radius);
        }
        foreach (Vec3i v in tunnel)
        {
            Tunnel(v.x, v.y, v.z, 2);
        }
    }