Esempio n. 1
0
        private void PlaceVoxel(VoxelHandle Vox, VoxelType Type, WorldManager World)
        {
            Vox.IsPlayerBuilt = true;
            Vox.Type          = Type;
            Vox.QuickSetLiquid(LiquidType.None, 0);

            for (int i = 0; i < 4; i++)
            {
                World.ParticleManager.Trigger("puff", MathFunctions.RandVector3Box(Vox.GetBoundingBox().Expand(0.25f)), Color.White, 5);
            }

            // Todo: Should this be handled by the chunk manager while processing voxel update events?
            foreach (var phys in World.EnumerateIntersectingObjects(Vox.GetBoundingBox(), CollisionType.Dynamic).OfType <Physics>())
            {
                phys.ApplyForce((phys.GlobalTransform.Translation - (Vox.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f))) * 100, 0.01f);
                BoundingBox     box     = Vox.GetBoundingBox();
                Physics.Contact contact = new Physics.Contact();
                Physics.TestStaticAABBAABB(box, phys.GetBoundingBox(), ref contact);

                if (!contact.IsIntersecting)
                {
                    continue;
                }

                Vector3 diff = contact.NEnter * contact.Penetration;
                Matrix  m    = phys.LocalTransform;
                m.Translation      += diff;
                phys.LocalTransform = m;
            }
        }
Esempio n. 2
0
        public void GenerateWater(VoxelChunk chunk, float maxHeight)
        {
            int waterHeight = Math.Min((int)(VoxelConstants.ChunkSizeY * NormalizeHeight(SeaLevel + 1.0f / VoxelConstants.ChunkSizeY, maxHeight)), VoxelConstants.ChunkSizeY - 1);
            var iceID       = VoxelLibrary.GetVoxelType("Ice");

            for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x)
            {
                for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z)
                {
                    var biome    = Overworld.GetBiomeAt(new Vector3(x, 0, z) + chunk.Origin, chunk.Manager.World.WorldScale, chunk.Manager.World.WorldOrigin);
                    var topVoxel = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle(
                                                                        chunk, new LocalVoxelCoordinate(x, VoxelConstants.ChunkSizeY - 1, z)));

                    for (var y = 0; y <= waterHeight; ++y)
                    {
                        var vox = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y, z));
                        if (vox.IsEmpty && y > topVoxel.Coordinate.Y)
                        {
                            if (biome.WaterSurfaceIce && y == waterHeight)
                            {
                                vox.RawSetType(iceID);
                            }
                            else
                            {
                                vox.QuickSetLiquid(biome.WaterIsLava ? LiquidType.Lava : LiquidType.Water, WaterManager.maxWaterLevel);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 3
0
 public void HandleLiquidInteraction(VoxelHandle Vox, LiquidType From, LiquidType To)
 {
     if ((From == LiquidType.Lava && To == LiquidType.Water) ||
         (From == LiquidType.Water && To == LiquidType.Lava))
     {
         Vox.Type = Library.GetVoxelType("Stone");
         Vox.QuickSetLiquid(LiquidType.None, 0);
     }
 }
Esempio n. 4
0
        public void GenerateWater(VoxelChunk chunk)
        {
            int waterHeight = (int)(SeaLevel * VoxelConstants.ChunkSizeY) + 1;
            var iceID       = VoxelLibrary.GetVoxelType("Ice");

            for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x)
            {
                for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z)
                {
                    var biome    = Overworld.GetBiomeAt(new Vector3(x, 0, z) + chunk.Origin, chunk.Manager.World.WorldScale, chunk.Manager.World.WorldOrigin);
                    var topVoxel = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle(
                                                                        chunk, new LocalVoxelCoordinate(x, VoxelConstants.ChunkSizeY - 1, z)));

                    for (var y = 0; y <= waterHeight; ++y)
                    {
                        var vox = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y, z));
                        if (vox.IsEmpty && y > topVoxel.Coordinate.Y)
                        {
                            if (biome.WaterSurfaceIce && y == waterHeight)
                            {
                                vox.RawSetType(iceID);
                            }
                            else
                            {
                                vox.QuickSetLiquid(LiquidType.Water, WaterManager.maxWaterLevel);
                            }
                        }
                    }

                    Vector2 vec = Overworld.WorldToOverworld(new Vector2(x + chunk.Origin.X, z + chunk.Origin.Z), chunk.Manager.World.WorldScale, chunk.Manager.World.WorldOrigin);


                    if (topVoxel.Coordinate.Y < VoxelConstants.ChunkSizeY - 1 &&
                        Overworld.GetWater(Overworld.Map, vec) == Overworld.WaterType.Volcano)
                    {
                        var localCoord = topVoxel.Coordinate.GetLocalVoxelCoordinate();
                        topVoxel = new VoxelHandle(topVoxel.Chunk, new LocalVoxelCoordinate(
                                                       localCoord.X, localCoord.Y + 1, localCoord.Z));

                        if (topVoxel.IsEmpty)
                        {
                            topVoxel.QuickSetLiquid(LiquidType.Lava, WaterManager.maxWaterLevel);
                        }
                    }
                }
            }
        }
Esempio n. 5
0
        public void GenerateLava(VoxelChunk chunk)
        {
            int lavaHeight = LavaLevel;

            for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x)
            {
                for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z)
                {
                    for (var y = 0; y < lavaHeight; ++y)
                    {
                        var voxel = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y, z));
                        if (voxel.IsEmpty && voxel.LiquidLevel == 0)
                        {
                            voxel.QuickSetLiquid(LiquidType.Lava, WaterManager.maxWaterLevel);
                        }
                    }
                }
            }
        }
Esempio n. 6
0
        private void DiscreteUpdate(ChunkManager ChunkManager, VoxelChunk chunk)
        {
            for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y)
            {
                // Apply 'liquid present' tracking in voxel data to skip entire slices.
                if (chunk.Data.LiquidPresent[y] == 0)
                {
                    continue;
                }

                var layerOrder = SlicePermutations[MathFunctions.RandInt(0, SlicePermutations.Length)];

                for (var i = 0; i < layerOrder.Length; ++i)
                {
                    var x            = layerOrder[i] % VoxelConstants.ChunkSizeX;
                    var z            = (layerOrder[i] >> VoxelConstants.XDivShift) % VoxelConstants.ChunkSizeZ;
                    var currentVoxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z));

                    if (currentVoxel.TypeID != 0)
                    {
                        continue;
                    }

                    if (currentVoxel.LiquidType == LiquidType.None || currentVoxel.LiquidLevel < 1)
                    {
                        continue;
                    }

                    // Evaporate.
                    if (currentVoxel.LiquidLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f))
                    {
                        if (currentVoxel.LiquidType == LiquidType.Lava)
                        {
                            currentVoxel.Type = Library.GetVoxelType("Stone");
                        }

                        NeedsMinimapUpdate = true;
                        currentVoxel.QuickSetLiquid(LiquidType.None, 0);
                        continue;
                    }

                    var voxBelow = ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(currentVoxel.Coordinate.X, currentVoxel.Coordinate.Y - 1, currentVoxel.Coordinate.Z));

                    if (voxBelow.IsValid && voxBelow.IsEmpty)
                    {
                        // Fall into the voxel below.

                        // Special case: No liquid below, just drop down.
                        if (voxBelow.LiquidType == LiquidType.None)
                        {
                            NeedsMinimapUpdate = true;
                            CreateSplash(currentVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType);
                            voxBelow.QuickSetLiquid(currentVoxel.LiquidType, currentVoxel.LiquidLevel);
                            currentVoxel.QuickSetLiquid(LiquidType.None, 0);
                            continue;
                        }

                        var belowType      = voxBelow.LiquidType;
                        var aboveType      = currentVoxel.LiquidType;
                        var spaceLeftBelow = maxWaterLevel - voxBelow.LiquidLevel;

                        if (spaceLeftBelow >= currentVoxel.LiquidLevel)
                        {
                            NeedsMinimapUpdate = true;
                            CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType);
                            voxBelow.LiquidLevel += currentVoxel.LiquidLevel;
                            currentVoxel.QuickSetLiquid(LiquidType.None, 0);
                            HandleLiquidInteraction(voxBelow, aboveType, belowType);
                            continue;
                        }

                        if (spaceLeftBelow > 0)
                        {
                            NeedsMinimapUpdate = true;
                            CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType);
                            currentVoxel.LiquidLevel = (byte)(currentVoxel.LiquidLevel - maxWaterLevel + voxBelow.LiquidLevel);
                            voxBelow.LiquidLevel     = maxWaterLevel;
                            HandleLiquidInteraction(voxBelow, aboveType, belowType);
                            continue;
                        }
                    }
                    else if (voxBelow.IsValid && currentVoxel.LiquidType == LiquidType.Lava && !voxBelow.IsEmpty && voxBelow.GrassType > 0)
                    {
                        voxBelow.GrassType = 0;
                    }

                    if (currentVoxel.LiquidLevel <= 1)
                    {
                        continue;
                    }

                    // Nothing left to do but spread.

                    RollArray(NeighborPermutations[MathFunctions.RandInt(0, NeighborPermutations.Length)], NeighborScratch, MathFunctions.RandInt(0, 4));

                    for (var n = 0; n < NeighborScratch.Length; ++n)
                    {
                        var neighborOffset = VoxelHelpers.ManhattanNeighbors2D[NeighborScratch[n]];
                        var neighborVoxel  = new VoxelHandle(Chunks, currentVoxel.Coordinate + neighborOffset);

                        if (neighborVoxel.IsValid && neighborVoxel.IsEmpty)
                        {
                            if (neighborVoxel.LiquidLevel < currentVoxel.LiquidLevel)
                            {
                                NeedsMinimapUpdate = true;
                                var amountToMove = (int)(currentVoxel.LiquidLevel * GetSpreadRate(currentVoxel.LiquidType));
                                if (neighborVoxel.LiquidLevel + amountToMove > maxWaterLevel)
                                {
                                    amountToMove = maxWaterLevel - neighborVoxel.LiquidLevel;
                                }

                                if (amountToMove > 2)
                                {
                                    CreateSplash(neighborVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType);
                                }

                                var newWater = currentVoxel.LiquidLevel - amountToMove;

                                var sourceType = currentVoxel.LiquidType;
                                var destType   = neighborVoxel.LiquidType;
                                currentVoxel.QuickSetLiquid(newWater == 0 ? LiquidType.None : sourceType, (byte)newWater);
                                neighborVoxel.QuickSetLiquid(destType == LiquidType.None ? sourceType : destType, (byte)(neighborVoxel.LiquidLevel + amountToMove));
                                HandleLiquidInteraction(neighborVoxel, sourceType, destType);
                                break;
                            }
                        }
                    }
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Creates a flat, wooden balloon port for the balloon to land on, and Dwarves to sit on.
        /// </summary>
        /// <param name="roomDes">The player's BuildRoom designator (so that we can create a balloon port)</param>
        /// <param name="chunkManager">The terrain handler</param>
        /// <param name="x">The position of the center of the balloon port</param>
        /// <param name="z">The position of the center of the balloon port</param>
        /// <param name="size">The size of the (square) balloon port in voxels on a side</param>
        public Room GenerateInitialBalloonPort(RoomBuilder roomDes, ChunkManager chunkManager, float x, float z,
                                               int size)
        {
            var centerCoordinate = GlobalVoxelCoordinate.FromVector3(new Vector3(x, VoxelConstants.ChunkSizeY - 1, z));

            var accumulator = 0;
            var count       = 0;

            for (var offsetX = -size; offsetX <= size; ++offsetX)
            {
                for (var offsetY = -size; offsetY <= size; ++offsetY)
                {
                    var topVoxel = VoxelHelpers.FindFirstVoxelBelowIncludeWater(
                        new VoxelHandle(chunkManager.ChunkData,
                                        centerCoordinate + new GlobalVoxelOffset(offsetX, 0, offsetY)));

                    if (topVoxel.Coordinate.Y > 0)
                    {
                        accumulator += topVoxel.Coordinate.Y + 1;
                        count       += 1;
                    }
                }
            }

            var averageHeight = (int)Math.Round(((float)accumulator / (float)count));

            if (StartUnderground)
            {
                accumulator = 0;
                count       = 0;
                List <string> illegalTypes = new List <string>()
                {
                    "Sand", "Dirt", "DarkDirt", "Ice"
                };
                for (var offsetX = -size; offsetX <= size; ++offsetX)
                {
                    for (var offsetY = -size; offsetY <= size; ++offsetY)
                    {
                        var topVoxel = VoxelHelpers.FindFirstVoxelBelow(
                            new VoxelHandle(chunkManager.ChunkData,
                                            centerCoordinate + new GlobalVoxelOffset(offsetX, 0, offsetY)));

                        if (topVoxel.Coordinate.Y > 0)
                        {
                            var vox = topVoxel;
                            for (int dy = topVoxel.Coordinate.Y; dy > 0; dy--)
                            {
                                vox = new VoxelHandle(chunkManager.ChunkData, new GlobalVoxelCoordinate(topVoxel.Coordinate.X, dy, topVoxel.Coordinate.Z));
                                if (vox.IsValid && !vox.IsEmpty && !illegalTypes.Contains(vox.Type.Name))
                                {
                                    break;
                                }
                            }
                            accumulator += vox.Coordinate.Y + 1;
                            count       += 1;
                        }
                    }
                }
                averageHeight = Math.Max((int)Math.Round(((float)accumulator / (float)count)) - 5, 0);
            }

            // Next, create the balloon port by deciding which voxels to fill.
            var balloonPortDesignations = new List <VoxelHandle>();
            var treasuryDesignations    = new List <VoxelHandle>();

            for (int dx = -size; dx <= size; dx++)
            {
                for (int dz = -size; dz <= size; dz++)
                {
                    Vector3 worldPos = new Vector3(centerCoordinate.X + dx, centerCoordinate.Y, centerCoordinate.Z + dz);

                    var baseVoxel = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle(
                                                                         chunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(worldPos)));

                    if (!baseVoxel.IsValid)
                    {
                        continue;
                    }

                    var h          = baseVoxel.Coordinate.Y + 1;
                    var localCoord = baseVoxel.Coordinate.GetLocalVoxelCoordinate();

                    for (int y = averageHeight; y < (StartUnderground ? averageHeight + 2 : h); y++)
                    {
                        var v = new VoxelHandle(baseVoxel.Chunk,
                                                new LocalVoxelCoordinate((int)localCoord.X, y, (int)localCoord.Z));
                        v.RawSetType(VoxelLibrary.GetVoxelType(0));
                        v.RawSetIsExplored();
                        v.QuickSetLiquid(LiquidType.None, 0);
                    }

                    if (averageHeight < h)
                    {
                        h = averageHeight;
                    }

                    bool isPosX = (dx == size && dz == 0);
                    bool isPosZ = (dz == size & dx == 0);
                    bool isNegX = (dx == -size && dz == 0);
                    bool isNegZ = (dz == -size && dz == 0);
                    bool isSide = (isPosX || isNegX || isPosZ || isNegZ);

                    Vector3 offset = Vector3.Zero;

                    if (isSide)
                    {
                        if (isPosX)
                        {
                            offset = Vector3.UnitX;
                        }
                        else if (isPosZ)
                        {
                            offset = Vector3.UnitZ;
                        }
                        else if (isNegX)
                        {
                            offset = -Vector3.UnitX;
                        }
                        else if (isNegZ)
                        {
                            offset = -Vector3.UnitZ;
                        }
                    }

                    bool encounteredFilled = false;
                    // Fill from the top height down to the bottom.
                    for (int y = Math.Min(0, h - 1); y < averageHeight && y < VoxelConstants.ChunkSizeY; y++)
                    {
                        var v = new VoxelHandle(baseVoxel.Chunk,
                                                new LocalVoxelCoordinate((int)localCoord.X, y, (int)localCoord.Z));
                        if (!v.IsValid)
                        {
                            throw new InvalidProgramException("Voxel was invalid while creating a new game's initial zones. This should not happen.");
                        }

                        v.RawSetType(VoxelLibrary.GetVoxelType("Scaffold"));
                        v.IsPlayerBuilt = true;
                        v.QuickSetLiquid(LiquidType.None, 0);

                        if (y == averageHeight - 1)
                        {
                            v.RawSetIsExplored();

                            if (dz >= 0)
                            {
                                balloonPortDesignations.Add(v);
                            }
                            else
                            {
                                treasuryDesignations.Add(v);
                            }
                        }

                        if (isSide && !encounteredFilled)
                        {
                            var ladderPos = new Vector3(worldPos.X, y, worldPos.Z) + offset +
                                            Vector3.One * 0.5f;
                            var ladderVox = new VoxelHandle(chunkManager.ChunkData,
                                                            GlobalVoxelCoordinate.FromVector3(ladderPos));
                            if (ladderVox.IsValid && ladderVox.IsEmpty)
                            {
                                var ladder = EntityFactory.CreateEntity <Ladder>("Ladder", ladderPos);
                                Master.Faction.OwnedObjects.Add(ladder);
                                ladder.Tags.Add("Moveable");
                                ladder.Tags.Add("Deconstructable");
                            }
                            else
                            {
                                encounteredFilled = true;
                            }
                        }
                    }
                }
            }

            // Actually create the BuildRoom.
            var toBuild = RoomLibrary.CreateRoom(PlayerFaction, "Balloon Port", this);

            roomDes.DesignatedRooms.Add(toBuild);
            RoomLibrary.CompleteRoomImmediately(toBuild, balloonPortDesignations);

            // Also add a treasury
            var treasury = RoomLibrary.CreateRoom(PlayerFaction, "Treasury", this);

            roomDes.DesignatedRooms.Add(treasury);
            RoomLibrary.CompleteRoomImmediately(treasury, treasuryDesignations);

            return(toBuild);
        }
        /// <summary>
        /// Creates a flat, wooden balloon port for the balloon to land on, and Dwarves to sit on.
        /// </summary>
        /// <param name="roomDes">The player's BuildRoom designator (so that we can create a balloon port)</param>
        /// <param name="chunkManager">The terrain handler</param>
        /// <param name="x">The position of the center of the balloon port</param>
        /// <param name="z">The position of the center of the balloon port</param>
        /// <param name="size">The size of the (square) balloon port in voxels on a side</param>
        public BalloonPort GenerateInitialBalloonPort(RoomBuilder roomDes, ChunkManager chunkManager, float x, float z,
                                                      int size)
        {
            var centerCoordinate = GlobalVoxelCoordinate.FromVector3(new Vector3(x, VoxelConstants.ChunkSizeY - 1, z));

            var accumulator = 0;
            var count       = 0;

            for (var offsetX = -size; offsetX <= size; ++offsetX)
            {
                for (var offsetY = -size; offsetY <= size; ++offsetY)
                {
                    var topVoxel = VoxelHelpers.FindFirstVoxelBelowIncludeWater(
                        new VoxelHandle(chunkManager.ChunkData,
                                        centerCoordinate + new GlobalVoxelOffset(offsetX, 0, offsetY)));

                    if (topVoxel.Coordinate.Y > 0)
                    {
                        accumulator += topVoxel.Coordinate.Y + 1;
                        count       += 1;
                    }
                }
            }

            var averageHeight = (int)Math.Round(((float)accumulator / (float)count));

            // Next, create the balloon port by deciding which voxels to fill.
            var balloonPortDesignations = new List <VoxelHandle>();
            var treasuryDesignations    = new List <VoxelHandle>();

            for (int dx = -size; dx <= size; dx++)
            {
                for (int dz = -size; dz <= size; dz++)
                {
                    Vector3 worldPos = new Vector3(centerCoordinate.X + dx, centerCoordinate.Y, centerCoordinate.Z + dz);

                    var baseVoxel = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle(
                                                                         chunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(worldPos)));

                    if (!baseVoxel.IsValid)
                    {
                        continue;
                    }

                    var h          = baseVoxel.Coordinate.Y + 1;
                    var localCoord = baseVoxel.Coordinate.GetLocalVoxelCoordinate();

                    for (int y = averageHeight; y < h; y++)
                    {
                        var v = new VoxelHandle(baseVoxel.Chunk,
                                                new LocalVoxelCoordinate((int)localCoord.X, y, (int)localCoord.Z));
                        v.RawSetType(VoxelLibrary.GetVoxelType(0));
                        v.QuickSetLiquid(LiquidType.None, 0);
                    }

                    if (averageHeight < h)
                    {
                        h = averageHeight;
                    }

                    bool isPosX = (dx == size && dz == 0);
                    bool isPosZ = (dz == size & dx == 0);
                    bool isNegX = (dx == -size && dz == 0);
                    bool isNegZ = (dz == -size && dz == 0);
                    bool isSide = (isPosX || isNegX || isPosZ || isNegZ);

                    Vector3 offset = Vector3.Zero;

                    if (isSide)
                    {
                        if (isPosX)
                        {
                            offset = Vector3.UnitX;
                        }
                        else if (isPosZ)
                        {
                            offset = Vector3.UnitZ;
                        }
                        else if (isNegX)
                        {
                            offset = -Vector3.UnitX;
                        }
                        else if (isNegZ)
                        {
                            offset = -Vector3.UnitZ;
                        }
                    }

                    // Fill from the top height down to the bottom.
                    for (int y = h - 1; y < averageHeight; y++)
                    {
                        var v = new VoxelHandle(baseVoxel.Chunk,
                                                new LocalVoxelCoordinate((int)localCoord.X, y, (int)localCoord.Z));
                        v.RawSetType(VoxelLibrary.GetVoxelType("Scaffold"));
                        v.QuickSetLiquid(LiquidType.None, 0);

                        if (y == averageHeight - 1)
                        {
                            if (dz >= 0)
                            {
                                balloonPortDesignations.Add(v);
                            }
                            else
                            {
                                treasuryDesignations.Add(v);
                            }
                        }

                        if (isSide)
                        {
                            var ladderPos = new Vector3(worldPos.X, y, worldPos.Z) + offset +
                                            Vector3.One * 0.5f;
                            var ladderVox = new VoxelHandle(chunkManager.ChunkData,
                                                            GlobalVoxelCoordinate.FromVector3(ladderPos));
                            if (ladderVox.IsValid && ladderVox.IsEmpty)
                            {
                                var ladder = EntityFactory.CreateEntity <Ladder>("Ladder", ladderPos);
                                Master.Faction.OwnedObjects.Add(ladder);
                                ladder.Tags.Add("Moveable");
                                ladder.Tags.Add("Deconstructable");
                            }
                        }
                    }
                }
            }

            // Actually create the BuildRoom.
            BalloonPort    toBuild  = new BalloonPort(PlayerFaction, balloonPortDesignations, this);
            BuildRoomOrder buildDes = new BuildRoomOrder(toBuild, roomDes.Faction, this);

            buildDes.Build(true);
            roomDes.DesignatedRooms.Add(toBuild);

            // Also add a treasury
            Treasury treasury = new Treasury(PlayerFaction, treasuryDesignations, this);

            treasury.OnBuilt();
            roomDes.DesignatedRooms.Add(treasury);

            return(toBuild);
        }