2012-06-14 09:06:06 -04:00
|
|
|
|
|
|
|
// FinishGen.cpp
|
|
|
|
|
|
|
|
/* Implements the various finishing generators:
|
|
|
|
- cFinishGenSnow
|
|
|
|
- cFinishGenIce
|
|
|
|
- cFinishGenSprinkleFoliage
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
|
|
|
|
#include "FinishGen.h"
|
2012-09-23 16:14:04 -04:00
|
|
|
#include "../BlockID.h"
|
2012-10-21 17:15:44 -04:00
|
|
|
#include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway()
|
2014-01-18 07:45:41 -05:00
|
|
|
#include "../Simulator/FireSimulator.h"
|
2013-03-14 05:52:57 -04:00
|
|
|
#include "../World.h"
|
2014-10-23 09:15:10 -04:00
|
|
|
#include "../IniFile.h"
|
2013-03-14 05:52:57 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-03-17 05:16:14 -04:00
|
|
|
#define DEF_NETHER_WATER_SPRINGS "0, 1; 255, 1"
|
2013-03-14 05:52:57 -04:00
|
|
|
#define DEF_NETHER_LAVA_SPRINGS "0, 0; 30, 0; 31, 50; 120, 50; 127, 0"
|
|
|
|
#define DEF_OVERWORLD_WATER_SPRINGS "0, 0; 10, 10; 11, 75; 16, 83; 20, 83; 24, 78; 32, 62; 40, 40; 44, 15; 48, 7; 56, 2; 64, 1; 255, 0"
|
|
|
|
#define DEF_OVERWORLD_LAVA_SPRINGS "0, 0; 10, 5; 11, 45; 48, 2; 64, 1; 255, 0"
|
2013-03-17 05:16:14 -04:00
|
|
|
#define DEF_END_WATER_SPRINGS "0, 1; 255, 1"
|
|
|
|
#define DEF_END_LAVA_SPRINGS "0, 1; 255, 1"
|
2012-06-14 09:06:06 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline bool IsWater(BLOCKTYPE a_BlockType)
|
|
|
|
{
|
|
|
|
return (a_BlockType == E_BLOCK_STATIONARY_WATER) || (a_BlockType == E_BLOCK_WATER);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2014-01-18 08:16:07 -05:00
|
|
|
// cFinishGenNetherClumpFoliage:
|
2014-01-10 10:31:45 -05:00
|
|
|
|
2014-01-18 08:16:07 -05:00
|
|
|
void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
|
2014-01-10 10:31:45 -05:00
|
|
|
{
|
2014-07-25 15:01:40 -04:00
|
|
|
int ChunkX = a_ChunkDesc.GetChunkX();
|
|
|
|
int ChunkZ = a_ChunkDesc.GetChunkZ();
|
2014-01-17 18:27:13 -05:00
|
|
|
|
2014-07-25 15:01:40 -04:00
|
|
|
int Val1 = m_Noise.IntNoise2DInt(ChunkX ^ ChunkZ, ChunkZ + ChunkX);
|
|
|
|
int Val2 = m_Noise.IntNoise2DInt(ChunkZ ^ ChunkX, ChunkZ - ChunkX);
|
2014-01-17 18:27:13 -05:00
|
|
|
|
2014-07-25 15:01:40 -04:00
|
|
|
int PosX = Val1 % 16;
|
|
|
|
int PosZ = Val2 % 16;
|
2014-01-17 18:27:13 -05:00
|
|
|
|
2014-01-17 16:58:01 -05:00
|
|
|
for (int y = 1; y < cChunkDef::Height; y++)
|
|
|
|
{
|
2014-01-17 18:27:13 -05:00
|
|
|
if (a_ChunkDesc.GetBlockType(PosX, y, PosZ) != E_BLOCK_AIR)
|
2014-01-17 16:58:01 -05:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2014-07-25 08:23:36 -04:00
|
|
|
|
2014-03-01 14:34:19 -05:00
|
|
|
if (!cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ))) // Only place on solid blocks
|
2014-01-17 16:58:01 -05:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-07-25 08:23:36 -04:00
|
|
|
// Choose what block to use.
|
|
|
|
NOISE_DATATYPE BlockType = m_Noise.IntNoise3D((int) ChunkX, y, (int) ChunkZ);
|
2014-01-18 07:45:41 -05:00
|
|
|
if (BlockType < -0.7)
|
2014-01-17 16:58:01 -05:00
|
|
|
{
|
2014-01-18 08:16:07 -05:00
|
|
|
TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_BROWN_MUSHROOM);
|
2014-01-17 16:58:01 -05:00
|
|
|
}
|
2014-01-18 07:45:41 -05:00
|
|
|
else if (BlockType < 0)
|
2014-01-17 16:58:01 -05:00
|
|
|
{
|
2014-01-18 08:16:07 -05:00
|
|
|
TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_RED_MUSHROOM);
|
2014-01-17 16:58:01 -05:00
|
|
|
}
|
2014-01-18 07:45:41 -05:00
|
|
|
else if (BlockType < 0.7)
|
2014-01-17 16:58:01 -05:00
|
|
|
{
|
2014-01-18 08:16:07 -05:00
|
|
|
TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_FIRE);
|
2014-01-17 16:58:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-10 10:31:45 -05:00
|
|
|
|
2014-01-17 16:58:01 -05:00
|
|
|
|
2014-01-18 08:17:26 -05:00
|
|
|
void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block)
|
2014-01-17 16:58:01 -05:00
|
|
|
{
|
2014-01-18 07:45:41 -05:00
|
|
|
bool IsFireBlock = a_Block == E_BLOCK_FIRE;
|
|
|
|
|
2014-07-27 05:59:54 -04:00
|
|
|
int MinX = a_RelX - 4;
|
|
|
|
if (MinX < 0) // Check if the coordinate is outside the chunk. If it it then adjust it.
|
|
|
|
{
|
|
|
|
MinX = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MaxX = a_RelX + 4;
|
|
|
|
if (MaxX > cChunkDef::Width) // Check if the coordinate is outside the chunk. If it it then adjust it.
|
|
|
|
{
|
|
|
|
MaxX = cChunkDef::Width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MinZ = a_RelZ - 4;
|
|
|
|
if (MinZ < 0) // Check if the coordinate is outside the chunk. If it it then adjust it.
|
|
|
|
{
|
|
|
|
MinZ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MaxZ = a_RelZ + 4;
|
|
|
|
if (MaxZ > cChunkDef::Width) // Check if the coordinate is outside the chunk. If it it then adjust it.
|
|
|
|
{
|
|
|
|
MaxZ = cChunkDef::Width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MinY = a_RelY - 2;
|
|
|
|
if (MinY < 0) // Check if the coordinate is outside the chunk. If it it then adjust it.
|
|
|
|
{
|
|
|
|
MinY = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MaxY = a_RelY + 2;
|
|
|
|
if (MaxY > cChunkDef::Height) // Check if the coordinate is outside the chunk. If it it then adjust it.
|
|
|
|
{
|
|
|
|
MaxY = cChunkDef::Height;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int x = MinX; x < MaxX; x++)
|
2014-01-10 10:31:45 -05:00
|
|
|
{
|
2014-07-25 08:23:36 -04:00
|
|
|
int xx = a_ChunkDesc.GetChunkX() * cChunkDef::Width + x;
|
2014-07-27 05:59:54 -04:00
|
|
|
for (int z = MinZ; z < MaxZ; z++)
|
2014-01-10 10:31:45 -05:00
|
|
|
{
|
2014-07-25 08:23:36 -04:00
|
|
|
int zz = a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z;
|
2014-07-27 05:59:54 -04:00
|
|
|
for (int y = MinY; y < MaxY; y++)
|
2014-01-10 10:31:45 -05:00
|
|
|
{
|
2014-06-04 15:01:05 -04:00
|
|
|
if (
|
|
|
|
((x < 0) || (x >= cChunkDef::Width)) ||
|
|
|
|
((y < 0) || (y >= cChunkDef::Height)) ||
|
|
|
|
((z < 0) || (z >= cChunkDef::Width))
|
|
|
|
)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
if (a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) // Don't replace non air blocks.
|
2014-01-10 10:31:45 -05:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2014-01-18 07:45:41 -05:00
|
|
|
|
|
|
|
BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z);
|
2014-07-27 14:48:39 -04:00
|
|
|
if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow)) // Only place on solid blocks
|
2014-01-10 10:31:45 -05:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
if (IsFireBlock) // don't place fire on non-forever burning blocks.
|
2014-01-18 07:45:41 -05:00
|
|
|
{
|
|
|
|
if (!cFireSimulator::DoesBurnForever(BlockBelow))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-25 08:23:36 -04:00
|
|
|
NOISE_DATATYPE Val = m_Noise.IntNoise2D(xx, zz);
|
|
|
|
if (Val < -0.5)
|
2014-01-10 10:31:45 -05:00
|
|
|
{
|
2014-01-17 18:27:13 -05:00
|
|
|
a_ChunkDesc.SetBlockType(x, y, z, a_Block);
|
2014-01-10 10:31:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-17 18:27:13 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-21 12:18:54 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// cFinishGenTallGrass:
|
2014-07-20 10:23:45 -04:00
|
|
|
|
2014-07-20 13:22:41 -04:00
|
|
|
void cFinishGenTallGrass::GenFinish(cChunkDesc & a_ChunkDesc)
|
2014-07-20 10:23:45 -04:00
|
|
|
{
|
2014-07-20 13:22:41 -04:00
|
|
|
for (int x = 0; x < cChunkDef::Width; x++)
|
2014-07-20 10:23:45 -04:00
|
|
|
{
|
2014-07-20 16:43:31 -04:00
|
|
|
int xx = x + a_ChunkDesc.GetChunkX() * cChunkDef::Width;
|
2014-07-20 13:22:41 -04:00
|
|
|
for (int z = 0; z < cChunkDef::Width; z++)
|
2014-07-20 10:23:45 -04:00
|
|
|
{
|
2014-07-20 16:43:31 -04:00
|
|
|
int zz = z + a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
|
|
|
|
int BiomeDensity = GetBiomeDensity(a_ChunkDesc.GetBiome(x, z));
|
|
|
|
|
2014-07-21 12:18:54 -04:00
|
|
|
// Choose if we want to place long grass here. If not then bail out:
|
2014-07-20 16:43:31 -04:00
|
|
|
if ((m_Noise.IntNoise2DInt(xx + m_Noise.IntNoise1DInt(xx), zz + m_Noise.IntNoise1DInt(zz)) / 7 % 100) > BiomeDensity)
|
2014-07-20 10:23:45 -04:00
|
|
|
{
|
2014-07-20 16:43:31 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-07-21 12:18:54 -04:00
|
|
|
// Get the top block + 1. This is the place where the grass would finaly be placed:
|
2014-07-21 10:01:16 -04:00
|
|
|
int y = a_ChunkDesc.GetHeight(x, z) + 1;
|
2014-11-10 15:55:13 -05:00
|
|
|
|
|
|
|
if (y >= 255)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2014-07-21 10:01:16 -04:00
|
|
|
|
2014-07-21 12:18:54 -04:00
|
|
|
// Check if long grass can be placed:
|
2014-07-21 10:01:16 -04:00
|
|
|
if (
|
|
|
|
(a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) ||
|
|
|
|
((a_ChunkDesc.GetBlockType(x, y - 1, z) != E_BLOCK_GRASS) && (a_ChunkDesc.GetBlockType(x, y - 1, z) != E_BLOCK_DIRT))
|
|
|
|
)
|
2014-07-20 16:43:31 -04:00
|
|
|
{
|
2014-07-21 10:01:16 -04:00
|
|
|
continue;
|
|
|
|
}
|
2014-07-20 16:43:31 -04:00
|
|
|
|
2014-07-21 12:18:54 -04:00
|
|
|
// Choose what long grass meta we should use:
|
2014-07-21 10:01:16 -04:00
|
|
|
int GrassType = m_Noise.IntNoise2DInt(xx * 50, zz * 50) / 7 % 100;
|
|
|
|
if (GrassType < 60)
|
|
|
|
{
|
|
|
|
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_TALL_GRASS, 1);
|
|
|
|
}
|
|
|
|
else if (GrassType < 90)
|
|
|
|
{
|
|
|
|
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_TALL_GRASS, 2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-07-21 12:18:54 -04:00
|
|
|
// If double long grass we have to choose what type we should use:
|
2014-07-21 10:01:16 -04:00
|
|
|
if (a_ChunkDesc.GetBlockType(x, y + 1, z) == E_BLOCK_AIR)
|
2014-07-20 16:43:31 -04:00
|
|
|
{
|
2014-07-21 10:01:16 -04:00
|
|
|
NIBBLETYPE Meta = (m_Noise.IntNoise2DInt(xx * 100, zz * 100) / 7 % 100) > 25 ? 2 : 3;
|
|
|
|
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_BIG_FLOWER, Meta);
|
|
|
|
a_ChunkDesc.SetBlockTypeMeta(x, y + 1, z, E_BLOCK_BIG_FLOWER, 8);
|
2014-07-20 10:23:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-21 10:34:35 -04:00
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2012-06-14 09:06:06 -04:00
|
|
|
// cFinishGenSprinkleFoliage:
|
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ)
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
// We'll be doing comparison to neighbors, so require the coords to be 1 block away from the chunk edges:
|
|
|
|
if (
|
|
|
|
(a_RelX < 1) || (a_RelX >= cChunkDef::Width - 1) ||
|
|
|
|
(a_RelY < 1) || (a_RelY >= cChunkDef::Height - 2) ||
|
|
|
|
(a_RelZ < 1) || (a_RelZ >= cChunkDef::Width - 1)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only allow dirt, grass or sand below sugarcane:
|
2013-03-17 13:55:03 -04:00
|
|
|
switch (a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
case E_BLOCK_DIRT:
|
|
|
|
case E_BLOCK_GRASS:
|
|
|
|
case E_BLOCK_SAND:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Water is required next to the block below the sugarcane:
|
|
|
|
if (
|
2013-03-17 13:55:03 -04:00
|
|
|
!IsWater(a_ChunkDesc.GetBlockType(a_RelX - 1, a_RelY, a_RelZ)) &&
|
|
|
|
!IsWater(a_ChunkDesc.GetBlockType(a_RelX + 1, a_RelY, a_RelZ)) &&
|
2014-07-18 03:57:34 -04:00
|
|
|
!IsWater(a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ - 1)) &&
|
|
|
|
!IsWater(a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ + 1))
|
2012-06-14 09:06:06 -04:00
|
|
|
)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// All conditions met, place a sugarcane here:
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(a_RelX, a_RelY + 1, a_RelZ, E_BLOCK_SUGARCANE);
|
2012-06-14 09:06:06 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
// Generate small foliage (1-block):
|
|
|
|
|
|
|
|
// TODO: Update heightmap with 1-block-tall foliage
|
2014-07-17 16:50:58 -04:00
|
|
|
for (int z = 0; z < cChunkDef::Width; z++)
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z;
|
2012-06-14 09:06:06 -04:00
|
|
|
const float zz = (float)BlockZ;
|
|
|
|
for (int x = 0; x < cChunkDef::Width; x++)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width + x;
|
|
|
|
if (((m_Noise.IntNoise2DInt(BlockX, BlockZ) / 8) % 128) < 124)
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-17 13:55:03 -04:00
|
|
|
int Top = a_ChunkDesc.GetHeight(x, z);
|
2012-06-14 09:06:06 -04:00
|
|
|
if (Top > 250)
|
|
|
|
{
|
|
|
|
// Nothing grows above Y=250
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-17 13:55:03 -04:00
|
|
|
if (a_ChunkDesc.GetBlockType(x, Top + 1, z) != E_BLOCK_AIR)
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
// Space already taken by something else, don't grow here
|
|
|
|
// WEIRD, since we're using heightmap, so there should NOT be anything above it
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const float xx = (float)BlockX;
|
2014-07-21 09:19:48 -04:00
|
|
|
float val1 = m_Noise.CubicNoise2D(xx * 0.1f, zz * 0.1f);
|
|
|
|
float val2 = m_Noise.CubicNoise2D(xx * 0.01f, zz * 0.01f);
|
2013-03-17 13:55:03 -04:00
|
|
|
switch (a_ChunkDesc.GetBlockType(x, Top, z))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
case E_BLOCK_GRASS:
|
|
|
|
{
|
2014-07-21 09:19:48 -04:00
|
|
|
float val3 = m_Noise.CubicNoise2D(xx * 0.01f + 10, zz * 0.01f + 10);
|
|
|
|
float val4 = m_Noise.CubicNoise2D(xx * 0.05f + 20, zz * 0.05f + 20);
|
2012-06-14 09:06:06 -04:00
|
|
|
if (val1 + val2 > 0.2f)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(x, ++Top, z, E_BLOCK_YELLOW_FLOWER);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
else if (val2 + val3 > 0.2f)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(x, ++Top, z, E_BLOCK_RED_ROSE);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
else if (val3 + val4 > 0.2f)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(x, ++Top, z, E_BLOCK_RED_MUSHROOM);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
else if (val1 + val4 > 0.2f)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(x, ++Top, z, E_BLOCK_BROWN_MUSHROOM);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
else if (val1 + val2 + val3 + val4 < -0.1)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockTypeMeta(x, ++Top, z, E_BLOCK_TALL_GRASS, E_META_TALL_GRASS_GRASS);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
2013-03-17 13:55:03 -04:00
|
|
|
else if (TryAddSugarcane(a_ChunkDesc, x, Top, z))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
++Top;
|
|
|
|
}
|
|
|
|
else if ((val1 > 0.5) && (val2 < -0.5))
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockTypeMeta(x, ++Top, z, E_BLOCK_PUMPKIN, (int)(val3 * 8) % 4);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
} // case E_BLOCK_GRASS
|
|
|
|
|
|
|
|
case E_BLOCK_SAND:
|
|
|
|
{
|
|
|
|
int y = Top + 1;
|
|
|
|
if (
|
|
|
|
(x > 0) && (x < cChunkDef::Width - 1) &&
|
|
|
|
(z > 0) && (z < cChunkDef::Width - 1) &&
|
|
|
|
(val1 + val2 > 0.5f) &&
|
2013-03-17 13:55:03 -04:00
|
|
|
(a_ChunkDesc.GetBlockType(x + 1, y, z) == E_BLOCK_AIR) &&
|
|
|
|
(a_ChunkDesc.GetBlockType(x - 1, y, z) == E_BLOCK_AIR) &&
|
|
|
|
(a_ChunkDesc.GetBlockType(x, y, z + 1) == E_BLOCK_AIR) &&
|
|
|
|
(a_ChunkDesc.GetBlockType(x, y, z - 1) == E_BLOCK_AIR)
|
2012-06-14 09:06:06 -04:00
|
|
|
)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(x, ++Top, z, E_BLOCK_CACTUS);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
2013-03-17 13:55:03 -04:00
|
|
|
else if (TryAddSugarcane(a_ChunkDesc, x, Top, z))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
++Top;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} // switch (TopBlock)
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetHeight(x, z, Top);
|
2012-06-14 09:06:06 -04:00
|
|
|
} // for y
|
|
|
|
} // for z
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2012-06-14 09:06:06 -04:00
|
|
|
// cFinishGenSnow:
|
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
// Add a snow block in snowy biomes onto blocks that can be snowed over
|
|
|
|
for (int z = 0; z < cChunkDef::Width; z++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < cChunkDef::Width; x++)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
switch (a_ChunkDesc.GetBiome(x, z))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
case biIcePlains:
|
|
|
|
case biIceMountains:
|
|
|
|
case biTaiga:
|
|
|
|
case biTaigaHills:
|
|
|
|
case biFrozenRiver:
|
|
|
|
case biFrozenOcean:
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
int Height = a_ChunkDesc.GetHeight(x, z);
|
2014-11-15 14:24:15 -05:00
|
|
|
if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) && (Height < cChunkDef::Height - 1))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
|
|
|
|
a_ChunkDesc.SetHeight(x, z, Height + 1);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2014-10-27 15:52:04 -04:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// There's no snow in the other biomes.
|
|
|
|
break;
|
|
|
|
}
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} // for z
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2012-06-14 09:06:06 -04:00
|
|
|
// cFinishGenIce:
|
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
void cFinishGenIce::GenFinish(cChunkDesc & a_ChunkDesc)
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
// Turn surface water into ice in icy biomes
|
|
|
|
for (int z = 0; z < cChunkDef::Width; z++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < cChunkDef::Width; x++)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
switch (a_ChunkDesc.GetBiome(x, z))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
case biIcePlains:
|
|
|
|
case biIceMountains:
|
|
|
|
case biTaiga:
|
|
|
|
case biTaigaHills:
|
|
|
|
case biFrozenRiver:
|
|
|
|
case biFrozenOcean:
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
int Height = a_ChunkDesc.GetHeight(x, z);
|
|
|
|
switch (a_ChunkDesc.GetBlockType(x, Height, z))
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
|
|
|
case E_BLOCK_WATER:
|
|
|
|
case E_BLOCK_STATIONARY_WATER:
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
a_ChunkDesc.SetBlockType(x, Height, z, E_BLOCK_ICE);
|
2012-06-14 09:06:06 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2014-10-27 15:53:16 -04:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// No icy water in other biomes.
|
|
|
|
break;
|
|
|
|
}
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} // for z
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-07-03 15:16:09 -04:00
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2014-07-29 09:24:11 -04:00
|
|
|
// cFinishGenSingleTopBlock:
|
2012-07-03 15:16:09 -04:00
|
|
|
|
2014-07-28 08:23:29 -04:00
|
|
|
int cFinishGenSingleTopBlock::GetNumToGen(const cChunkDef::BiomeMap & a_BiomeMap)
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
|
|
|
int res = 0;
|
2013-12-20 10:01:34 -05:00
|
|
|
for (size_t i = 0; i < ARRAYCOUNT(a_BiomeMap); i++)
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
2014-07-28 08:23:29 -04:00
|
|
|
if (IsAllowedBiome(a_BiomeMap[i]))
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
|
|
|
res++;
|
|
|
|
}
|
|
|
|
} // for i - a_BiomeMap[]
|
2013-03-17 13:55:03 -04:00
|
|
|
return m_Amount * res / 256;
|
2012-07-03 15:16:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-28 08:23:29 -04:00
|
|
|
void cFinishGenSingleTopBlock::GenFinish(cChunkDesc & a_ChunkDesc)
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
int NumToGen = GetNumToGen(a_ChunkDesc.GetBiomeMap());
|
|
|
|
int ChunkX = a_ChunkDesc.GetChunkX();
|
|
|
|
int ChunkZ = a_ChunkDesc.GetChunkZ();
|
|
|
|
for (int i = 0; i < NumToGen; i++)
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
int x = (m_Noise.IntNoise3DInt(ChunkX + ChunkZ, ChunkZ, i) / 13) % cChunkDef::Width;
|
|
|
|
int z = (m_Noise.IntNoise3DInt(ChunkX - ChunkZ, i, ChunkZ) / 11) % cChunkDef::Width;
|
2012-07-03 15:16:09 -04:00
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
// Place the block at {x, z} if possible:
|
2014-07-28 08:23:29 -04:00
|
|
|
EMCSBiome Biome = a_ChunkDesc.GetBiome(x, z);
|
|
|
|
if (!IsAllowedBiome(Biome))
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
// Incorrect biome
|
2012-07-03 15:16:09 -04:00
|
|
|
continue;
|
|
|
|
}
|
2014-07-28 08:23:29 -04:00
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
int Height = a_ChunkDesc.GetHeight(x, z);
|
2014-11-30 12:44:44 -05:00
|
|
|
if (Height >= cChunkDef::Height - 1)
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
|
|
|
// Too high up
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-17 13:55:03 -04:00
|
|
|
if (a_ChunkDesc.GetBlockType(x, Height + 1, z) != E_BLOCK_AIR)
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
// Not an empty block
|
2012-07-03 15:16:09 -04:00
|
|
|
continue;
|
|
|
|
}
|
2014-07-28 08:23:29 -04:00
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, Height, z);
|
2014-07-28 08:23:29 -04:00
|
|
|
if (!IsAllowedBlockBelow(BlockBelow))
|
2012-07-03 15:16:09 -04:00
|
|
|
{
|
2014-07-28 08:23:29 -04:00
|
|
|
continue;
|
2013-03-17 13:55:03 -04:00
|
|
|
}
|
2014-07-28 08:23:29 -04:00
|
|
|
|
|
|
|
a_ChunkDesc.SetBlockType(x, Height + 1, z, m_BlockType);
|
|
|
|
a_ChunkDesc.SetHeight(x, z, Height + 1);
|
|
|
|
}
|
2012-07-03 15:16:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2012-07-27 17:00:11 -04:00
|
|
|
// cFinishGenBottomLava:
|
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
void cFinishGenBottomLava::GenFinish(cChunkDesc & a_ChunkDesc)
|
2012-07-27 17:00:11 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
|
2012-07-27 17:00:11 -04:00
|
|
|
for (int y = m_Level; y > 0; y--)
|
|
|
|
{
|
|
|
|
for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
|
|
|
{
|
|
|
|
int Index = cChunkDef::MakeIndexNoCheck(x, y, z);
|
2013-03-17 13:55:03 -04:00
|
|
|
if (BlockTypes[Index] == E_BLOCK_AIR)
|
2012-07-27 17:00:11 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
BlockTypes[Index] = E_BLOCK_STATIONARY_LAVA;
|
2012-07-27 17:00:11 -04:00
|
|
|
}
|
|
|
|
} // for x, for z
|
|
|
|
} // for y
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-10-21 16:06:31 -04:00
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2012-10-21 16:06:31 -04:00
|
|
|
// cFinishGenPreSimulator:
|
|
|
|
|
2014-07-30 07:06:48 -04:00
|
|
|
cFinishGenPreSimulator::cFinishGenPreSimulator(bool a_PreSimulateFallingBlocks, bool a_PreSimulateWater, bool a_PreSimulateLava) :
|
|
|
|
m_PreSimulateFallingBlocks(a_PreSimulateFallingBlocks),
|
|
|
|
m_PreSimulateWater(a_PreSimulateWater),
|
|
|
|
m_PreSimulateLava(a_PreSimulateLava)
|
2012-10-21 16:06:31 -04:00
|
|
|
{
|
|
|
|
// Nothing needed yet
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
void cFinishGenPreSimulator::GenFinish(cChunkDesc & a_ChunkDesc)
|
2012-10-21 16:06:31 -04:00
|
|
|
{
|
2014-07-30 07:06:48 -04:00
|
|
|
if (m_PreSimulateFallingBlocks)
|
|
|
|
{
|
|
|
|
CollapseSandGravel(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_PreSimulateWater)
|
|
|
|
{
|
|
|
|
StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_PreSimulateLava)
|
|
|
|
{
|
|
|
|
StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA);
|
|
|
|
}
|
2012-10-21 16:06:31 -04:00
|
|
|
// TODO: other operations
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cFinishGenPreSimulator::CollapseSandGravel(
|
|
|
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
|
|
|
cChunkDef::HeightMap & a_HeightMap // Height map to update by the current data
|
|
|
|
)
|
|
|
|
{
|
|
|
|
for (int z = 0; z < cChunkDef::Width; z++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < cChunkDef::Width; x++)
|
|
|
|
{
|
|
|
|
int LastY = -1;
|
2013-03-03 10:02:50 -05:00
|
|
|
int HeightY = 0;
|
2012-10-21 16:06:31 -04:00
|
|
|
for (int y = 0; y < cChunkDef::Height; y++)
|
|
|
|
{
|
|
|
|
BLOCKTYPE Block = cChunkDef::GetBlock(a_BlockTypes, x, y, z);
|
|
|
|
switch (Block)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
// Set the last block onto which stuff can fall to this height:
|
|
|
|
LastY = y;
|
2013-03-03 10:02:50 -05:00
|
|
|
HeightY = y;
|
2012-10-21 16:06:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case E_BLOCK_AIR:
|
2013-03-03 10:02:50 -05:00
|
|
|
{
|
|
|
|
// Do nothing
|
|
|
|
break;
|
|
|
|
}
|
2013-03-02 12:08:58 -05:00
|
|
|
case E_BLOCK_FIRE:
|
2012-12-22 05:45:23 -05:00
|
|
|
case E_BLOCK_WATER:
|
|
|
|
case E_BLOCK_STATIONARY_WATER:
|
|
|
|
case E_BLOCK_LAVA:
|
|
|
|
case E_BLOCK_STATIONARY_LAVA:
|
2012-10-21 16:06:31 -04:00
|
|
|
{
|
2013-03-03 10:02:50 -05:00
|
|
|
// Do nothing, only remember this height as potentially highest
|
|
|
|
HeightY = y;
|
2012-10-21 16:06:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case E_BLOCK_SAND:
|
|
|
|
case E_BLOCK_GRAVEL:
|
|
|
|
{
|
|
|
|
if (LastY < y - 1)
|
|
|
|
{
|
|
|
|
cChunkDef::SetBlock(a_BlockTypes, x, LastY + 1, z, Block);
|
|
|
|
cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR);
|
|
|
|
}
|
|
|
|
LastY++;
|
2013-03-03 10:02:50 -05:00
|
|
|
if (LastY > HeightY)
|
|
|
|
{
|
|
|
|
HeightY = LastY;
|
|
|
|
}
|
2012-10-21 16:06:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} // switch (GetBlock)
|
|
|
|
} // for y
|
2013-03-03 10:02:50 -05:00
|
|
|
cChunkDef::SetHeight(a_HeightMap, x, z, HeightY);
|
2012-10-21 16:06:31 -04:00
|
|
|
} // for x
|
|
|
|
} // for z
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-10-21 17:15:44 -04:00
|
|
|
|
|
|
|
void cFinishGenPreSimulator::StationarizeFluid(
|
|
|
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
|
|
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read
|
|
|
|
BLOCKTYPE a_Fluid,
|
|
|
|
BLOCKTYPE a_StationaryFluid
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// Turn fluid in the middle to stationary, unless it has air or washable block next to it:
|
|
|
|
for (int z = 1; z < cChunkDef::Width - 1; z++)
|
|
|
|
{
|
|
|
|
for (int x = 1; x < cChunkDef::Width - 1; x++)
|
|
|
|
{
|
|
|
|
for (int y = cChunkDef::GetHeight(a_HeightMap, x, z); y >= 0; y--)
|
|
|
|
{
|
|
|
|
BLOCKTYPE Block = cChunkDef::GetBlock(a_BlockTypes, x, y, z);
|
|
|
|
if ((Block != a_Fluid) && (Block != a_StationaryFluid))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
int x, y, z;
|
|
|
|
} Coords[] =
|
|
|
|
{
|
|
|
|
{1, 0, 0},
|
|
|
|
{-1, 0, 0},
|
|
|
|
{0, 0, 1},
|
|
|
|
{0, 0, -1},
|
|
|
|
{0, -1, 0}
|
|
|
|
} ;
|
|
|
|
BLOCKTYPE BlockToSet = a_StationaryFluid; // By default, don't simulate this block
|
2013-12-20 10:01:34 -05:00
|
|
|
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
2012-10-21 17:15:44 -04:00
|
|
|
{
|
|
|
|
if ((y == 0) && (Coords[i].y < 0))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
BLOCKTYPE Neighbor = cChunkDef::GetBlock(a_BlockTypes, x + Coords[i].x, y + Coords[i].y, z + Coords[i].z);
|
|
|
|
if ((Neighbor == E_BLOCK_AIR) || cFluidSimulator::CanWashAway(Neighbor))
|
|
|
|
{
|
|
|
|
// There is an air / washable neighbor, simulate this block
|
|
|
|
BlockToSet = a_Fluid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} // for i - Coords[]
|
|
|
|
cChunkDef::SetBlock(a_BlockTypes, x, y, z, BlockToSet);
|
|
|
|
} // for y
|
|
|
|
} // for x
|
|
|
|
} // for z
|
|
|
|
|
|
|
|
// Turn fluid at the chunk edges into non-stationary fluid:
|
|
|
|
for (int y = 0; y < cChunkDef::Height; y++)
|
|
|
|
{
|
2013-03-03 10:02:50 -05:00
|
|
|
for (int i = 0; i < cChunkDef::Width; i++) // i stands for both x and z here
|
2012-10-21 17:15:44 -04:00
|
|
|
{
|
|
|
|
if (cChunkDef::GetBlock(a_BlockTypes, 0, y, i) == a_StationaryFluid)
|
|
|
|
{
|
|
|
|
cChunkDef::SetBlock(a_BlockTypes, 0, y, i, a_Fluid);
|
|
|
|
}
|
|
|
|
if (cChunkDef::GetBlock(a_BlockTypes, i, y, 0) == a_StationaryFluid)
|
|
|
|
{
|
|
|
|
cChunkDef::SetBlock(a_BlockTypes, i, y, 0, a_Fluid);
|
|
|
|
}
|
|
|
|
if (cChunkDef::GetBlock(a_BlockTypes, cChunkDef::Width - 1, y, i) == a_StationaryFluid)
|
|
|
|
{
|
|
|
|
cChunkDef::SetBlock(a_BlockTypes, cChunkDef::Width - 1, y, i, a_Fluid);
|
|
|
|
}
|
|
|
|
if (cChunkDef::GetBlock(a_BlockTypes, i, y, cChunkDef::Width - 1) == a_StationaryFluid)
|
|
|
|
{
|
|
|
|
cChunkDef::SetBlock(a_BlockTypes, i, y, cChunkDef::Width - 1, a_Fluid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-11-11 10:35:49 -05:00
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2013-03-14 05:52:57 -04:00
|
|
|
// cFinishGenFluidSprings:
|
|
|
|
|
2014-01-10 16:22:54 -05:00
|
|
|
cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension) :
|
2013-03-14 05:52:57 -04:00
|
|
|
m_Noise(a_Seed + a_Fluid * 100), // Need to take fluid into account, otherwise water and lava springs generate next to each other
|
|
|
|
m_HeightDistribution(255),
|
|
|
|
m_Fluid(a_Fluid)
|
|
|
|
{
|
|
|
|
bool IsWater = (a_Fluid == E_BLOCK_WATER);
|
|
|
|
AString SectionName = IsWater ? "WaterSprings" : "LavaSprings";
|
|
|
|
AString DefaultHeightDistribution;
|
2014-01-07 08:24:25 -05:00
|
|
|
int DefaultChance = 0;
|
2014-01-10 16:22:54 -05:00
|
|
|
switch (a_Dimension)
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
2013-06-22 14:41:08 -04:00
|
|
|
case dimNether:
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
DefaultHeightDistribution = IsWater ? DEF_NETHER_WATER_SPRINGS : DEF_NETHER_LAVA_SPRINGS;
|
|
|
|
DefaultChance = IsWater ? 0 : 15;
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 14:41:08 -04:00
|
|
|
case dimOverworld:
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
DefaultHeightDistribution = IsWater ? DEF_OVERWORLD_WATER_SPRINGS : DEF_OVERWORLD_LAVA_SPRINGS;
|
|
|
|
DefaultChance = IsWater ? 24 : 9;
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 14:41:08 -04:00
|
|
|
case dimEnd:
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
DefaultHeightDistribution = IsWater ? DEF_END_WATER_SPRINGS : DEF_END_LAVA_SPRINGS;
|
|
|
|
DefaultChance = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
ASSERT(!"Unhandled world dimension");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} // switch (dimension)
|
|
|
|
AString HeightDistribution = a_IniFile.GetValueSet(SectionName, "HeightDistribution", DefaultHeightDistribution);
|
2013-03-17 05:16:14 -04:00
|
|
|
if (!m_HeightDistribution.SetDefString(HeightDistribution) || (m_HeightDistribution.GetSum() <= 0))
|
|
|
|
{
|
2014-07-17 16:50:58 -04:00
|
|
|
LOGWARNING("[%sSprings]: HeightDistribution is invalid, using the default of \"%s\".",
|
2013-03-17 05:16:14 -04:00
|
|
|
(a_Fluid == E_BLOCK_WATER) ? "Water" : "Lava",
|
|
|
|
DefaultHeightDistribution.c_str()
|
|
|
|
);
|
|
|
|
m_HeightDistribution.SetDefString(DefaultHeightDistribution);
|
|
|
|
}
|
2013-03-14 05:52:57 -04:00
|
|
|
m_Chance = a_IniFile.GetValueSetI(SectionName, "Chance", DefaultChance);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-03-17 13:55:03 -04:00
|
|
|
void cFinishGenFluidSprings::GenFinish(cChunkDesc & a_ChunkDesc)
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
int ChanceRnd = (m_Noise.IntNoise3DInt(128 * a_ChunkDesc.GetChunkX(), 512, 256 * a_ChunkDesc.GetChunkZ()) / 13) % 100;
|
2013-03-14 05:52:57 -04:00
|
|
|
if (ChanceRnd > m_Chance)
|
|
|
|
{
|
|
|
|
// Not in this chunk
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the height at which to try:
|
2013-03-17 13:55:03 -04:00
|
|
|
int Height = m_Noise.IntNoise3DInt(128 * a_ChunkDesc.GetChunkX(), 1024, 256 * a_ChunkDesc.GetChunkZ()) / 11;
|
2013-03-14 05:52:57 -04:00
|
|
|
Height %= m_HeightDistribution.GetSum();
|
|
|
|
Height = m_HeightDistribution.MapValue(Height);
|
|
|
|
|
|
|
|
// Try adding the spring at the height, if unsuccessful, move lower:
|
|
|
|
for (int y = Height; y > 1; y--)
|
|
|
|
{
|
|
|
|
// TODO: randomize the order in which the coords are being checked
|
|
|
|
for (int z = 1; z < cChunkDef::Width - 1; z++)
|
|
|
|
{
|
|
|
|
for (int x = 1; x < cChunkDef::Width - 1; x++)
|
|
|
|
{
|
2013-03-17 13:55:03 -04:00
|
|
|
switch (a_ChunkDesc.GetBlockType(x, y, z))
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
case E_BLOCK_NETHERRACK:
|
|
|
|
case E_BLOCK_STONE:
|
|
|
|
{
|
2013-03-19 04:32:02 -04:00
|
|
|
if (TryPlaceSpring(a_ChunkDesc, x, y, z))
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
// Succeeded, bail out
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // switch (BlockType)
|
|
|
|
} // for x
|
|
|
|
} // for y
|
|
|
|
} // for y
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-03-19 04:32:02 -04:00
|
|
|
bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int y, int z)
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
// In order to place a spring, it needs exactly one of the XZ neighbors or a below neighbor to be air
|
|
|
|
// Also, its neighbor on top of it must be non-air
|
2013-03-19 04:32:02 -04:00
|
|
|
if (a_ChunkDesc.GetBlockType(x, y + 1, z) == E_BLOCK_AIR)
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
int x, y, z;
|
|
|
|
} Coords[] =
|
|
|
|
{
|
|
|
|
{-1, 0, 0},
|
|
|
|
{ 1, 0, 0},
|
|
|
|
{ 0, -1, 0},
|
|
|
|
{ 0, 0, -1},
|
|
|
|
{ 0, 0, 1},
|
|
|
|
} ;
|
|
|
|
int NumAirNeighbors = 0;
|
2013-12-20 10:01:34 -05:00
|
|
|
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
2013-03-19 04:32:02 -04:00
|
|
|
switch (a_ChunkDesc.GetBlockType(x + Coords[i].x, y + Coords[i].y, z + Coords[i].z))
|
2013-03-14 05:52:57 -04:00
|
|
|
{
|
|
|
|
case E_BLOCK_AIR:
|
|
|
|
{
|
|
|
|
NumAirNeighbors += 1;
|
|
|
|
if (NumAirNeighbors > 1)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NumAirNeighbors == 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Has exactly one air neighbor, place a spring:
|
2013-03-19 04:32:02 -04:00
|
|
|
a_ChunkDesc.SetBlockTypeMeta(x, y, z, m_Fluid, 0);
|
2013-03-14 05:52:57 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|