-
-
Notifications
You must be signed in to change notification settings - Fork 632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Animal terrain finisher #1642
Animal terrain finisher #1642
Changes from 13 commits
9831220
2d93274
978c996
585662e
8d7c2d4
6803df1
2ea8a36
7f8f2f1
d348433
8c3b9ae
83d4bec
a36e766
b7c4ef0
99a5b38
53a3359
538991c
78f0aeb
bd8c185
c655d97
750b4a3
a8bbd5e
b25fcb0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ mgueydan | |
MikeHunsinger | ||
mtilden | ||
nesco | ||
p-mcgowan | ||
rs2k | ||
SamJBarney | ||
Sofapriester | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
||
|
||
|
||
|
@@ -400,7 +402,7 @@ void cFinishGenSoulsandRims::GenFinish(cChunkDesc & a_ChunkDesc) | |
int ChunkZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; | ||
HEIGHTTYPE MaxHeight = a_ChunkDesc.GetMaxHeight(); | ||
|
||
for (int x = 0; x < 16; x++) | ||
for (int x = 0; x < 16; x++) | ||
{ | ||
int xx = ChunkX + x; | ||
for (int z = 0; z < 16; z++) | ||
|
@@ -943,3 +945,225 @@ 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"); | ||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You say you're using the default, but I see no code doing that. |
||
} | ||
} | ||
|
||
|
||
|
||
|
||
|
||
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) / 7) % cChunkDef::Width; | ||
int PackCenterZ = (m_Noise.IntNoise2DInt(chunkX, chunkZ) / 7) % cChunkDef::Width; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't work well, the noise functions return the same number for the same input coords. You should add |
||
if (TrySpawnAnimals(a_ChunkDesc, PackCenterX, a_ChunkDesc.GetHeight(PackCenterX, PackCenterZ), PackCenterZ, RandomMob)) | ||
{ | ||
for (int i = 0; i < 5; i++) | ||
{ | ||
int OffsetX = (m_Noise.IntNoise2DInt(chunkX + chunkZ, Tries) / 7) % cChunkDef::Width; | ||
int OffsetZ = (m_Noise.IntNoise2DInt(chunkX, chunkZ + Tries) / 7) % cChunkDef::Width; | ||
TrySpawnAnimals(a_ChunkDesc, OffsetX, a_ChunkDesc.GetHeight(OffsetX, OffsetZ), OffsetZ, RandomMob); | ||
} | ||
return; | ||
|
||
} // if pack center spawn successful | ||
} // for tries | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still not good here. The |
||
} | ||
|
||
|
||
|
||
|
||
|
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will fail if the spawning is requested at a_RelY = 0 or a_RelY = 255 (it may happen for some custom terrain generator settings). |
||
|
||
// 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)) | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When breaking conditions on separate lines, put the first condition on a separate line as well: 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))) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Condition formatting - separate first line, closing parenthesis on next line. |
||
return false; | ||
} | ||
if (AnimalToSpawn == mtMooshroom && BlockUnderFeet != E_BLOCK_MYCELIUM) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Condition formatting - use parenthesis around each comparison. |
||
{ | ||
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) / 7) % cChunkDef::Width; | ||
int z = (m_Noise.IntNoise2DInt(chunkX, chunkZ) / 7) % cChunkDef::Width; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will generate the same coords - |
||
|
||
/** Check biomes first to get a list of animals */ | ||
switch (a_ChunkDesc.GetBiome(x, z)) | ||
{ | ||
// No animals | ||
case biNether: | ||
case biEnd: | ||
{ | ||
return mtInvalidType; | ||
} | ||
// Squid only | ||
case biOcean: | ||
case biFrozenOcean: | ||
case biFrozenRiver: | ||
case biRiver: | ||
case biDeepOcean: | ||
{ | ||
ListOfSpawnables.insert(MobIter, mtSquid); | ||
break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use braces for the case contents as well. |
||
} | ||
// Mooshroom only | ||
case biMushroomIsland: | ||
case biMushroomShore: | ||
{ | ||
ListOfSpawnables.insert(MobIter, mtMooshroom); | ||
break; | ||
} | ||
case biJungle: | ||
case biJungleHills: | ||
case biJungleEdge: | ||
case biJungleM: | ||
case biJungleEdgeM: | ||
{ | ||
ListOfSpawnables.insert(MobIter, mtOcelot); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably missing a |
||
case biPlains: | ||
case biSunflowerPlains: | ||
case biSavanna: | ||
case biSavannaPlateau: | ||
case biSavannaM: | ||
case biSavannaPlateauM: | ||
{ | ||
ListOfSpawnables.insert(MobIter, mtHorse); | ||
// ListOfSpawnables.insert(mtDonkey); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing |
||
// Wolves only | ||
case biForest: | ||
case biTaiga: | ||
case biMegaTaiga: | ||
case biColdTaiga: | ||
case biColdTaigaM: | ||
{ | ||
ListOfSpawnables.insert(MobIter, mtWolf); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing |
||
// All other mobs | ||
default: | ||
{ | ||
ListOfSpawnables.insert(MobIter, mtChicken); | ||
ListOfSpawnables.insert(MobIter, mtCow); | ||
ListOfSpawnables.insert(MobIter, mtPig); | ||
ListOfSpawnables.insert(MobIter, mtSheep); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default mobs should probably added to all biomes, shouldn't they? Why not take them out of the |
||
} | ||
|
||
if (ListOfSpawnables.empty()) | ||
{ | ||
return mtInvalidType; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should not log this situation, it's perfectly normal for an |
||
|
||
int RandMob = (m_Noise.IntNoise2DInt(chunkX, chunkZ) / 7) % ListOfSpawnables.size(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This random value is tightly coupled with the |
||
MobIter=ListOfSpawnables.begin(); | ||
for (int i = 0; i < RandMob; i++) | ||
{ | ||
++MobIter; | ||
} | ||
|
||
return *MobIter; | ||
} | ||
|
||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,8 @@ | |
#include "ComposableGenerator.h" | ||
#include "../Noise/Noise.h" | ||
#include "../ProbabDistrib.h" | ||
#include "../Mobs/Monster.h" | ||
#include "FastRandom.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FastRandom should not be needed anymore, is it? |
||
|
||
|
||
|
||
|
@@ -121,7 +123,7 @@ class cFinishGenSoulsandRims : | |
public cFinishGen | ||
{ | ||
public: | ||
cFinishGenSoulsandRims(int a_Seed) : | ||
cFinishGenSoulsandRims(int a_Seed) : | ||
m_Noise(a_Seed) | ||
{ | ||
} | ||
|
@@ -308,10 +310,39 @@ class cFinishGenFluidSprings : | |
// 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not a good candidate for doxy-comment, it's just a note about where the original function comes from, it doesn't explain what it does. This comment should use regular C++ comment style ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To explain further: These functions should be doxy-commented in the base class, where it should be explained what they're used for and what can be achieved by overriding them. Then, the individual overrides would just repeat the description, going out of date really easily. So instead they just point to the original class. With multi-level and sometimes even multiple inheritance, this helps folks who don't have an IDE capable of searching for the parent. |
||
|
||
// 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment is wrong, the function doesn't spawn any more animals. |
||
|
||
// Gets a random animal from biome-dependant list | ||
eMonsterType GetRandomMob(cChunkDesc & a_ChunkDesc); | ||
} ; | ||
|
||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indenting is wrong inside the switch, there's a needless extra level.