summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--src/Generating/ComposableGenerator.cpp6
-rw-r--r--src/Generating/FinishGen.cpp235
-rw-r--r--src/Generating/FinishGen.h32
-rw-r--r--src/World.cpp2
5 files changed, 273 insertions, 3 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index fffc55b2a..9a0a675e7 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -18,6 +18,7 @@ mgueydan
MikeHunsinger
mtilden
nesco
+p-mcgowan
rs2k
SamJBarney
Sofapriester
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 6b8923955..bda45ad92 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -294,7 +294,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{
// 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 BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index ec487db53..41dbdca16 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -26,6 +26,8 @@
#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_LAVA_SPRINGS "0, 1; 255, 1"
+#define DEF_ANIMAL_SPAWN_PERCENT 10
+#define DEF_NO_ANIMALS 0
@@ -958,3 +960,236 @@ 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);
+ }
+}
+
+
+
+
+
+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;
+}
+
+
+
+
diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h
index f568d18bb..8305908c0 100644
--- a/src/Generating/FinishGen.h
+++ b/src/Generating/FinishGen.h
@@ -18,6 +18,7 @@
#include "ComposableGenerator.h"
#include "../Noise/Noise.h"
#include "../ProbabDistrib.h"
+#include "../Mobs/Monster.h"
@@ -311,10 +312,39 @@ protected:
// cFinishGen 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);
} ;
+
+/** 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);
+} ;
+
+
+
+
diff --git a/src/World.cpp b/src/World.cpp
index 7518327b9..4a741d37b 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -747,7 +747,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
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;
}
case dimNether: