diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 59a65a537..35e44363e 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -31,6 +31,7 @@ #include "Blocks/BlockHandler.h" #include "Simulator/FluidSimulator.h" #include "MobCensus.h" +#include "MobSpawner.h" #include @@ -468,6 +469,42 @@ void cChunk::CollectMobCensus(cMobCensus& toFill) +void cChunk::getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ) +{ + assert(a_MaxX * a_MaxY * a_MaxZ * 8 < 0x00ffffff); + int Random = m_World->GetTickRandomNumber(0x00ffffff); + a_X = Random % (a_MaxX * 2); + a_Y = (Random / (a_MaxX * 2)) % (a_MaxY * 2); + a_Z = ((Random / (a_MaxX * 2)) / (a_MaxY * 2)) % (a_MaxZ * 2); + a_X /= 2; + a_Y /= 2; + a_Z /= 2; +} + + + + + +void cChunk::getRandomBlock(int& a_X, int& a_Y, int& a_Z) +{ + // MG TODO : check if this kind of optimization (only one random call) is still needed + // MG TODO : if so propagate it + + getThreeRandomNumber(a_X, a_Y, a_Z, Width, Height-2, Width); + a_Y++; +} + + + + + +void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) +{ +} + + + + void cChunk::Tick(float a_Dt) { diff --git a/source/Chunk.h b/source/Chunk.h index 5f2bba3d8..69ecbfec4 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -50,6 +50,7 @@ class cChunkDataSerializer; class cBlockArea; class cFluidSimulatorData; class cMobCensus; +class cMobSpawner; typedef std::list cClientHandleList; typedef cItemCallback cEntityCallback; @@ -128,6 +129,9 @@ public: /// Recence all mobs proximities to players in order to know what to do with them void CollectMobCensus(cMobCensus& toFill); + /// Try to Spawn Monsters inside chunk + void SpawnMobs(cMobSpawner& a_MobSpawner); + void Tick(float a_Dt); int GetPosX(void) const { return m_PosX; } @@ -389,6 +393,10 @@ private: cSandSimulatorChunkData m_SandSimulatorData; + // pick up a random block of this chunk + void getRandomBlock(int& a_X, int& a_Y, int& a_Z); + void getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ); + void RemoveBlockEntity(cBlockEntity * a_BlockEntity); void AddBlockEntity (cBlockEntity * a_BlockEntity); diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index 610b293b5..f5cbacdc7 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -13,6 +13,7 @@ #include "PluginManager.h" #include "Entities/TNTEntity.h" #include "MobCensus.h" +#include "MobSpawner.h" #ifndef _WIN32 #include // abs @@ -2167,6 +2168,19 @@ void cChunkMap::CollectMobCensus(cMobCensus& a_ToFill) +void cChunkMap::SpawnMobs(cMobSpawner& a_MobSpawner) +{ + cCSLock Lock(m_CSLayers); + for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) + { + (*itr)->SpawnMobs(a_MobSpawner); + } // for itr - m_Layers +} + + + + + void cChunkMap::Tick(float a_Dt) { cCSLock Lock(m_CSLayers); @@ -2343,6 +2357,20 @@ void cChunkMap::cChunkLayer::CollectMobCensus(cMobCensus& a_ToFill) +void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner& a_MobSpawner) +{ + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + // We only spawn close to players + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) + { + m_Chunks[i]->SpawnMobs(a_MobSpawner); + } + } // for i - m_Chunks[] +} + + + void cChunkMap::cChunkLayer::Tick(float a_Dt) { for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) diff --git a/source/ChunkMap.h b/source/ChunkMap.h index c9d9abf75..168f54b39 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -27,6 +27,7 @@ class cPickup; class cChunkDataSerializer; class cBlockArea; class cMobCensus; +class cMobSpawner; typedef std::list cClientHandleList; typedef cChunk * cChunkPtr; @@ -264,12 +265,15 @@ public: /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call + /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); /// Make a Mob census, of all mobs, their family, their chunk and theyr distance to closest player void CollectMobCensus(cMobCensus& a_ToFill); + /// Try to Spawn Monsters inside all Chunks + void SpawnMobs(cMobSpawner& a_MobSpawner); + void Tick(float a_Dt); void UnloadUnusedChunks(void); @@ -314,8 +318,9 @@ private: void UnloadUnusedChunks(void); /// Collect a mob census, of all mobs, their megatype, their chunk and their distance o closest player - void CollectMobCensus(cMobCensus& a_ToFill); - + void CollectMobCensus(cMobCensus& a_ToFill); + /// Try to Spawn Monsters inside all Chunks + void SpawnMobs(cMobSpawner& a_MobSpawner); void Tick(float a_Dt); diff --git a/source/MobSpawner.h b/source/MobSpawner.h new file mode 100644 index 000000000..7498c567d --- /dev/null +++ b/source/MobSpawner.h @@ -0,0 +1,28 @@ + +#pragma once + +#include +#include "BlockID.h" +#include "ChunkDef.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 + +class cChunk; +class cEntity; + + +// This class is used to determine wich monster can be spawned on wich place +// it is essentially static (f.i. Squids spawn in water, Zombie spawn in dark places) +// but it also has dynamic part depending on the world.ini +class cMobSpawner +{ +public : + // constructor + // a_MobFamily is the mega type of mobs that this spawner will spawn + // a_AllowedTypes is the set of types allowed for mobs it will spawn. Empty set + // would result in no spawn at all + // Allowed mobs thah are not of the right Megatype will not be include (no warning) + cMobSpawner(cMonster::eFamily MobFamily, const std::set& a_AllowedTypes); + + +};