diff options
-rw-r--r-- | source/Chunk.cpp | 37 | ||||
-rw-r--r-- | source/Chunk.h | 1 | ||||
-rw-r--r-- | source/MobSpawner.cpp | 140 | ||||
-rw-r--r-- | source/MobSpawner.h | 5 |
4 files changed, 99 insertions, 84 deletions
diff --git a/source/Chunk.cpp b/source/Chunk.cpp index c9d457af3..c419cf7f2 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -519,32 +519,29 @@ void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) ASSERT(Try_Y > 0); ASSERT(Try_Y < cChunkDef::Height-1); - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - BLOCKTYPE BlockType_below; - NIBBLETYPE BlockMeta_below; - BLOCKTYPE BlockType_above; - NIBBLETYPE BlockMeta_above; - if (UnboundedRelGetBlock(Try_X, Try_Y , Try_Z, BlockType, BlockMeta) && - UnboundedRelGetBlock(Try_X, Try_Y-1, Try_Z, BlockType_below, BlockMeta_below)&& - UnboundedRelGetBlock(Try_X, Try_Y+1, Try_Z, BlockType_above, BlockMeta_above) - ) - { - EMCSBiome Biome = m_ChunkMap->GetBiomeAt (Try_X, Try_Z); - // MG TODO : - // Moon cycle (for slime) - // check player and playerspawn presence < 24 blocks - // check mobs presence on the block + EMCSBiome Biome = m_ChunkMap->GetBiomeAt (Try_X, Try_Z); + // MG TODO : + // Moon cycle (for slime) + // check player and playerspawn presence < 24 blocks + // check mobs presence on the block - // MG TODO: fix the "light" thing, I'm pretty sure that UnboundedRelGetBlock s not returning the right thing + // MG TODO : check that "Level" really means Y + + NIBBLETYPE SkyLight = 0; - // MG TODO : check that "Level" really means Y - cEntity* newMob = a_MobSpawner.TryToSpawnHere(BlockType, BlockMeta, BlockType_below, BlockMeta_below, BlockType_above, BlockMeta_above, Biome, Try_Y, MaxNbOfSuccess); + NIBBLETYPE BlockLight = 0; + + if (IsLightValid()) + { + int TimeOfDay = m_World->GetTimeOfDay(); + cEntity* newMob = a_MobSpawner.TryToSpawnHere(this, Try_X, Try_Y, Try_Z, Biome, TimeOfDay, MaxNbOfSuccess); if (newMob) { int WorldX, WorldY, WorldZ; PositionToWorldPosition(Try_X, Try_Y, Try_Z, WorldX, WorldY, WorldZ); - newMob->SetPosition(WorldX, WorldY, WorldZ); + double ActualX = WorldX + 0.5; + double ActualZ = WorldZ + 0.5; + newMob->SetPosition(ActualX, WorldY, ActualZ); LOGD("Spawning %s #%i at %d,%d,%d",newMob->GetClass(),newMob->GetUniqueID(),WorldX, WorldY, WorldZ); NumberOfSuccess++; } diff --git a/source/Chunk.h b/source/Chunk.h index ab110c7cb..591e29ad9 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -329,6 +329,7 @@ public: /// Same as QueueTickBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s in such a case), ignores unsuccessful attempts void UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ); + // Simulator data: cFireSimulatorChunkData & GetFireSimulatorData (void) { return m_FireSimulatorData; } cFluidSimulatorData * GetWaterSimulatorData(void) { return m_WaterSimulatorData; } diff --git a/source/MobSpawner.cpp b/source/MobSpawner.cpp index 1b3796f70..7dff56d61 100644 --- a/source/MobSpawner.cpp +++ b/source/MobSpawner.cpp @@ -124,87 +124,103 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) -bool cMobSpawner::CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level) +bool cMobSpawner::CanSpawnHere(const cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, int a_TimeOfDay, EMCSBiome a_Biome) { - bool toReturn = false; - std::set<cMonster::eType>::iterator itr = m_AllowedTypes.find(a_MobType); - if (itr != m_AllowedTypes.end()) + BLOCKTYPE TargetBlock; + BLOCKTYPE BlockAbove; + BLOCKTYPE BlockBelow; + NIBBLETYPE BlockLight; + NIBBLETYPE SkyLight; + if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock)) { - // MG TODO : find a nicer paging - if (a_MobType == cMonster::mtSquid) - { - toReturn = ( - IsBlockLiquid(a_BlockType) && - a_Level >= 45 && - a_Level <= 62 - ); - } - else if (a_MobType == cMonster::mtBat) - { - toReturn = a_Level <= 60; // MG TODO : find a real rule - } - else + + a_Chunk->UnboundedRelGetBlockBlockLight(a_RelX, a_RelY, a_RelZ, BlockLight); + a_Chunk->UnboundedRelGetBlockSkyLight(a_RelX, a_RelY, a_RelZ, SkyLight); + a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY + 1, a_RelZ, BlockAbove); + a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, BlockBelow); + switch(a_MobType) { - if ( - a_BlockType == E_BLOCK_AIR && - a_BlockType_above == E_BLOCK_AIR && - ! (g_BlockTransparent[a_BlockType_below]) - ) + case cMonster::mtSquid: + return IsBlockWater(TargetBlock) && (a_RelY >= 45) && (a_RelY <= 62); + + case cMonster::mtBat: + return (a_RelY <= 63) && (BlockLight <= 4) && (SkyLight <= 4 || a_TimeOfDay > 12500) && (TargetBlock == E_BLOCK_AIR) && (!g_BlockTransparent[BlockAbove]); + + case cMonster::mtChicken: + case cMonster::mtCow: + case cMonster::mtPig: + case cMonster::mtHorse: + case cMonster::mtSheep: { - if (a_MobType == cMonster::mtChicken || a_MobType == cMonster::mtPig || a_MobType == cMonster::mtCow || a_MobType == cMonster::mtSheep) - { - toReturn = ( - a_BlockType_below == E_BLOCK_GRASS /*&& // MG TODO - a_LightLevel >= 9 */ - ); - } - else if (a_MobType == cMonster::mtOcelot) + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + (BlockBelow == E_BLOCK_GRASS) && (SkyLight >= 9) && (a_TimeOfDay <= 12500); + } + + case cMonster::mtOcelot: + { + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && + ((BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES)) && (a_RelY >= 62) && (m_Random.NextInt(3,a_Biome) != 0); + } + case cMonster::mtEnderman: + { + if (a_RelY < 250) { - toReturn = ( - a_Level >= 62 && - ( - a_BlockType_below == E_BLOCK_GRASS || - a_BlockType_below == E_BLOCK_LEAVES - ) && - m_Random.NextInt(3,a_Biome) != 0 - ); + BLOCKTYPE BlockTop; + a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY + 2, a_RelZ, BlockTop); + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (BlockTop == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + ((SkyLight <= 7) || a_TimeOfDay > 12500 ) && (BlockLight <= 7) ; } - else if (a_MobType == cMonster::mtCreeper || a_MobType == cMonster::mtSkeleton || a_MobType == cMonster::mtZombie || a_MobType == cMonster::mtSpider || a_MobType == cMonster::mtEnderman || a_MobType == cMonster::mtZombiePigman) + break; + } + case cMonster::mtSpider: + { + bool CanSpawn = true; + bool HaveFloor = false; + for (int x = 0; x < 2; ++x) { - toReturn = true /*a_LightLevel <= 7 MG TODO*/; - /*if (a_SunLight) MG TODO + for(int z = 0; z < 2; ++z) { - if (m_Random.NextInt(2,a_Biome) != 0) + CanSpawn = a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY, a_RelZ + z, TargetBlock); + CanSpawn = CanSpawn && (TargetBlock == E_BLOCK_AIR); + if (!CanSpawn) { - toReturn = false; + return false; } - }*/ - } - else if (a_MobType == cMonster::mtSlime) - { - toReturn = a_Level <= 40; - // MG TODO : much more complicated rules - } - else if (a_MobType == cMonster::mtGhast) - { - toReturn = m_Random.NextInt(20,a_Biome) == 0; - } - else - { - LOGD("MG TODO : check I've got a Rule to write for type %d",a_MobType); - toReturn = true; + if (!HaveFloor) + { + a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock); + HaveFloor = HaveFloor || !g_BlockTransparent[TargetBlock]; + } + } } + return CanSpawn && HaveFloor && ((SkyLight <= 7) || a_TimeOfDay > 12500) && (BlockLight <= 7); + } + case cMonster::mtCreeper: + case cMonster::mtZombie: + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + ((SkyLight <= 7) || a_TimeOfDay > 12500) && (BlockLight <= 7) && (m_Random.NextInt(2,a_Biome) == 0); + + case cMonster::mtSlime: + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + ((a_RelY <= 40) || a_Biome == biSwampland); + case cMonster::mtGhast: + case cMonster::mtZombiePigman: + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + (m_Random.NextInt(20,a_Biome) == 0); + default: + LOGD("MG TODO : check I've got a Rule to write for type %d",a_MobType); + return false; } } - return toReturn; + return false; } -cMonster* cMobSpawner::TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level, int& a_MaxPackSize) +cMonster* cMobSpawner::TryToSpawnHere(const cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int a_TimeOfDay, int& a_MaxPackSize) { cMonster* toReturn = NULL; if (m_NewPack) @@ -226,7 +242,7 @@ cMonster* cMobSpawner::TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockM } - if (CanSpawnHere(m_MobType, a_BlockType, a_BlockMeta, a_BlockType_below, a_BlockMeta_below, a_BlockType_above, a_BlockMeta_above, a_Biome, a_Level)) + if (CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_TimeOfDay, a_Biome)) { cMonster * newMob = cMonster::NewMonsterFromType(m_MobType); if (newMob) diff --git a/source/MobSpawner.h b/source/MobSpawner.h index ba2a18f2e..3b9ede7c6 100644 --- a/source/MobSpawner.h +++ b/source/MobSpawner.h @@ -4,6 +4,7 @@ #include <set> #include "BlockID.h" #include "ChunkDef.h" +#include "Chunk.h" #include "FastRandom.h" #include "Mobs/Monster.h" //this is a side-effect of keeping Mobfamily inside Monster class. I'd prefer to keep both (Mobfamily and Monster) inside a "Monster" namespace MG TODO : do it @@ -38,7 +39,7 @@ public : // if this is the first of a Pack : determine the type of monster // BlockType & BlockMeta are used to decide what kind of Mob can Spawn here // MaxPackSize is set to the maximal size for a pack this type of mob - cMonster * TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level, int& a_MaxPackSize); + cMonster * TryToSpawnHere(const cChunk * a_Chunk, int A_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int a_TimeOfDay, int& a_MaxPackSize); // mark the beginning of a new Pack // all mobs of the same Pack are the same type @@ -52,7 +53,7 @@ public : protected : // return true if specified type of mob can spawn on specified block - bool CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level); + bool CanSpawnHere(const cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, int a_TimeOfDay, EMCSBiome a_Biome); // return a random type that can spawn on specified biome. // returns E_ENTITY_TYPE_DONOTUSE if none is possible |