Merge pull request #1642 from p-mcgowan/animalTerrainFinisher
Animal terrain finisher
This commit is contained in:
commit
5712fadf31
@ -18,6 +18,7 @@ mgueydan
|
|||||||
MikeHunsinger
|
MikeHunsinger
|
||||||
mtilden
|
mtilden
|
||||||
nesco
|
nesco
|
||||||
|
p-mcgowan
|
||||||
rs2k
|
rs2k
|
||||||
SamJBarney
|
SamJBarney
|
||||||
Sofapriester
|
Sofapriester
|
||||||
|
@ -294,7 +294,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
|||||||
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
|
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
|
||||||
{
|
{
|
||||||
// Finishers, alpha-sorted:
|
// Finishers, alpha-sorted:
|
||||||
if (NoCaseCompare(*itr, "BottomLava") == 0)
|
if (NoCaseCompare(*itr, "Animals") == 0)
|
||||||
|
{
|
||||||
|
m_FinishGens.push_back(cFinishGenPtr(new cFinishGenPassiveMobs(Seed, a_IniFile, Dimension)));
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(*itr, "BottomLava") == 0)
|
||||||
{
|
{
|
||||||
int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
|
int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
|
||||||
int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
|
int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
#define DEF_OVERWORLD_LAVA_SPRINGS "0, 0; 10, 5; 11, 45; 48, 2; 64, 1; 255, 0"
|
#define DEF_OVERWORLD_LAVA_SPRINGS "0, 0; 10, 5; 11, 45; 48, 2; 64, 1; 255, 0"
|
||||||
#define DEF_END_WATER_SPRINGS "0, 1; 255, 1"
|
#define DEF_END_WATER_SPRINGS "0, 1; 255, 1"
|
||||||
#define DEF_END_LAVA_SPRINGS "0, 1; 255, 1"
|
#define DEF_END_LAVA_SPRINGS "0, 1; 255, 1"
|
||||||
|
#define DEF_ANIMAL_SPAWN_PERCENT 10
|
||||||
|
#define DEF_NO_ANIMALS 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -958,3 +960,237 @@ bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cFinishGenPassiveMobs:
|
||||||
|
|
||||||
|
cFinishGenPassiveMobs::cFinishGenPassiveMobs(int a_Seed, cIniFile & a_IniFile, eDimension a_Dimension) :
|
||||||
|
m_Noise(a_Seed)
|
||||||
|
{
|
||||||
|
AString SectionName = "Animals";
|
||||||
|
int DefaultAnimalSpawnChunkPercentage = DEF_ANIMAL_SPAWN_PERCENT;
|
||||||
|
switch (a_Dimension)
|
||||||
|
{
|
||||||
|
case dimOverworld:
|
||||||
|
{
|
||||||
|
DefaultAnimalSpawnChunkPercentage = DEF_ANIMAL_SPAWN_PERCENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case dimNether:
|
||||||
|
case dimEnd: // No nether or end animals (currently)
|
||||||
|
{
|
||||||
|
DefaultAnimalSpawnChunkPercentage = DEF_NO_ANIMALS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ASSERT(!"Unhandled world dimension");
|
||||||
|
DefaultAnimalSpawnChunkPercentage = DEF_NO_ANIMALS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (dimension)
|
||||||
|
m_AnimalProbability = a_IniFile.GetValueSetI(SectionName, "AnimalSpawnChunkPercentage", DefaultAnimalSpawnChunkPercentage);
|
||||||
|
if ((m_AnimalProbability < 0) || (m_AnimalProbability > 100))
|
||||||
|
{
|
||||||
|
LOGWARNING("[Animals]: AnimalSpawnChunkPercentage is invalid, using the default of \"%d\".", DefaultAnimalSpawnChunkPercentage);
|
||||||
|
m_AnimalProbability = DefaultAnimalSpawnChunkPercentage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFinishGenPassiveMobs::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
int chunkX = a_ChunkDesc.GetChunkX();
|
||||||
|
int chunkZ = a_ChunkDesc.GetChunkZ();
|
||||||
|
int ChanceRnd = (m_Noise.IntNoise2DInt(chunkX, chunkZ) / 7) % 100;
|
||||||
|
if (ChanceRnd > m_AnimalProbability)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMonsterType RandomMob = GetRandomMob(a_ChunkDesc);
|
||||||
|
if (RandomMob == mtInvalidType)
|
||||||
|
{
|
||||||
|
LOGWARNING("Attempted to spawn invalid mob type.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try spawning a pack center 10 times, should get roughly the same probability
|
||||||
|
for (int Tries = 0; Tries < 10; Tries++)
|
||||||
|
{
|
||||||
|
int PackCenterX = (m_Noise.IntNoise2DInt(chunkX + chunkZ, Tries) / 7) % cChunkDef::Width;
|
||||||
|
int PackCenterZ = (m_Noise.IntNoise2DInt(chunkX, chunkZ + Tries) / 7) % cChunkDef::Width;
|
||||||
|
if (TrySpawnAnimals(a_ChunkDesc, PackCenterX, a_ChunkDesc.GetHeight(PackCenterX, PackCenterZ), PackCenterZ, RandomMob))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
int OffsetX = (m_Noise.IntNoise2DInt(chunkX + chunkZ + i, Tries) / 7) % cChunkDef::Width;
|
||||||
|
int OffsetZ = (m_Noise.IntNoise2DInt(chunkX, chunkZ + Tries + i) / 7) % cChunkDef::Width;
|
||||||
|
TrySpawnAnimals(a_ChunkDesc, OffsetX, a_ChunkDesc.GetHeight(OffsetX, OffsetZ), OffsetZ, RandomMob);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
} // if pack center spawn successful
|
||||||
|
} // for tries
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cFinishGenPassiveMobs::TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, eMonsterType AnimalToSpawn)
|
||||||
|
{
|
||||||
|
if ((a_RelY >= cChunkDef::Height - 1) || (a_RelY <= 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCKTYPE BlockAtHead = a_ChunkDesc.GetBlockType(a_RelX, a_RelY + 1, a_RelZ);
|
||||||
|
BLOCKTYPE BlockAtFeet = a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ);
|
||||||
|
BLOCKTYPE BlockUnderFeet = a_ChunkDesc.GetBlockType(a_RelX, a_RelY - 1, a_RelZ);
|
||||||
|
|
||||||
|
// Check block below (opaque, grass, water), and above (air)
|
||||||
|
if ((AnimalToSpawn == mtSquid) && (BlockAtFeet != E_BLOCK_WATER))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(AnimalToSpawn != mtSquid) &&
|
||||||
|
(BlockAtHead != E_BLOCK_AIR) &&
|
||||||
|
(BlockAtFeet != E_BLOCK_AIR) &&
|
||||||
|
(!cBlockInfo::IsTransparent(BlockUnderFeet))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(BlockUnderFeet != E_BLOCK_GRASS) &&
|
||||||
|
((AnimalToSpawn == mtSheep) || (AnimalToSpawn == mtChicken) || (AnimalToSpawn == mtPig))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((AnimalToSpawn == mtMooshroom) && (BlockUnderFeet != E_BLOCK_MYCELIUM))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AnimalX, AnimalY, AnimalZ;
|
||||||
|
AnimalX = (double)(a_ChunkDesc.GetChunkX()*cChunkDef::Width + a_RelX + 0.5);
|
||||||
|
AnimalY = a_RelY;
|
||||||
|
AnimalZ = (double)(a_ChunkDesc.GetChunkZ()*cChunkDef::Width + a_RelZ + 0.5);
|
||||||
|
|
||||||
|
cEntityList ChunkEntities = a_ChunkDesc.GetEntities();
|
||||||
|
cMonster * NewMob = cMonster::NewMonsterFromType(AnimalToSpawn);
|
||||||
|
NewMob->SetPosition(AnimalX, AnimalY, AnimalZ);
|
||||||
|
ChunkEntities.push_back(NewMob);
|
||||||
|
LOGD("Spawning %s #%i at {%d, %d, %d}", NewMob->GetClass(), NewMob->GetUniqueID(), AnimalX, AnimalY, AnimalZ);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
eMonsterType cFinishGenPassiveMobs::GetRandomMob(cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
|
||||||
|
std::set<eMonsterType> ListOfSpawnables;
|
||||||
|
std::set<eMonsterType>::iterator MobIter = ListOfSpawnables.begin();
|
||||||
|
int chunkX = a_ChunkDesc.GetChunkX();
|
||||||
|
int chunkZ = a_ChunkDesc.GetChunkZ();
|
||||||
|
int x = (m_Noise.IntNoise2DInt(chunkX, chunkZ + 10) / 7) % cChunkDef::Width;
|
||||||
|
int z = (m_Noise.IntNoise2DInt(chunkX + chunkZ, chunkZ) / 7) % cChunkDef::Width;
|
||||||
|
|
||||||
|
/** Check biomes first to get a list of animals */
|
||||||
|
switch (a_ChunkDesc.GetBiome(x, z))
|
||||||
|
{
|
||||||
|
// No animals in deserts or non-overworld dimensions
|
||||||
|
case biNether:
|
||||||
|
case biEnd:
|
||||||
|
case biDesertHills:
|
||||||
|
case biDesert:
|
||||||
|
case biDesertM:
|
||||||
|
{
|
||||||
|
return mtInvalidType;
|
||||||
|
}
|
||||||
|
// Mooshroom only - no other mobs on mushroom islands
|
||||||
|
case biMushroomIsland:
|
||||||
|
case biMushroomShore:
|
||||||
|
{
|
||||||
|
return mtMooshroom;
|
||||||
|
}
|
||||||
|
// Add squid in ocean biomes
|
||||||
|
case biOcean:
|
||||||
|
case biFrozenOcean:
|
||||||
|
case biFrozenRiver:
|
||||||
|
case biRiver:
|
||||||
|
case biDeepOcean:
|
||||||
|
{
|
||||||
|
ListOfSpawnables.insert(MobIter, mtSquid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Add ocelots in jungle biomes
|
||||||
|
case biJungle:
|
||||||
|
case biJungleHills:
|
||||||
|
case biJungleEdge:
|
||||||
|
case biJungleM:
|
||||||
|
case biJungleEdgeM:
|
||||||
|
{
|
||||||
|
ListOfSpawnables.insert(MobIter, mtOcelot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case biPlains:
|
||||||
|
case biSunflowerPlains:
|
||||||
|
case biSavanna:
|
||||||
|
case biSavannaPlateau:
|
||||||
|
case biSavannaM:
|
||||||
|
case biSavannaPlateauM:
|
||||||
|
{
|
||||||
|
ListOfSpawnables.insert(MobIter, mtHorse);
|
||||||
|
// ListOfSpawnables.insert(mtDonkey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Add wolves in forest and spruce forests
|
||||||
|
case biForest:
|
||||||
|
case biTaiga:
|
||||||
|
case biMegaTaiga:
|
||||||
|
case biColdTaiga:
|
||||||
|
case biColdTaigaM:
|
||||||
|
{
|
||||||
|
ListOfSpawnables.insert(MobIter, mtWolf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Nothing special about this biome
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ListOfSpawnables.insert(MobIter, mtChicken);
|
||||||
|
ListOfSpawnables.insert(MobIter, mtCow);
|
||||||
|
ListOfSpawnables.insert(MobIter, mtPig);
|
||||||
|
ListOfSpawnables.insert(MobIter, mtSheep);
|
||||||
|
|
||||||
|
if (ListOfSpawnables.empty())
|
||||||
|
{
|
||||||
|
return mtInvalidType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RandMob = (m_Noise.IntNoise2DInt(chunkX - chunkZ + 2, chunkX + 5) / 7) % ListOfSpawnables.size();
|
||||||
|
MobIter = ListOfSpawnables.begin();
|
||||||
|
for (int i = 0; i < RandMob; i++)
|
||||||
|
{
|
||||||
|
++MobIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *MobIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "ComposableGenerator.h"
|
#include "ComposableGenerator.h"
|
||||||
#include "../Noise/Noise.h"
|
#include "../Noise/Noise.h"
|
||||||
#include "../ProbabDistrib.h"
|
#include "../ProbabDistrib.h"
|
||||||
|
#include "../Mobs/Monster.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -311,10 +312,39 @@ protected:
|
|||||||
// cFinishGen override:
|
// cFinishGen override:
|
||||||
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
||||||
|
|
||||||
/// Tries to place a spring at the specified coords, checks neighbors. Returns true if successful
|
// Tries to place a spring at the specified coords, checks neighbors. Returns true if successful
|
||||||
bool TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int y, int z);
|
bool TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int y, int z);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** This class populates generated chunks with packs of biome-dependant animals
|
||||||
|
Animals: cows, sheep, pigs, mooshrooms, squid, horses, wolves, ocelots
|
||||||
|
*/
|
||||||
|
class cFinishGenPassiveMobs :
|
||||||
|
public cFinishGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cFinishGenPassiveMobs(int a_Seed, cIniFile & a_IniFile, eDimension a_Dimension);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
cNoise m_Noise;
|
||||||
|
int m_AnimalProbability; // Chance, [0..100], that an animal pack will be generated in a chunk
|
||||||
|
|
||||||
|
// cFinishGen override:
|
||||||
|
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
||||||
|
|
||||||
|
// Returns false if an animal cannot spawn at given coords, else adds it to the chunk's entity list and returns true
|
||||||
|
bool TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int x, int y, int z, eMonsterType AnimalToSpawn);
|
||||||
|
|
||||||
|
// Gets a random animal from biome-dependant list
|
||||||
|
eMonsterType GetRandomMob(cChunkDesc & a_ChunkDesc);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -747,7 +747,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
|
|||||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
|
a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
|
||||||
a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
|
a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
|
||||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal");
|
a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal");
|
||||||
a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
|
a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator, Animals");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case dimNether:
|
case dimNether:
|
||||||
|
Loading…
Reference in New Issue
Block a user