diff options
-rw-r--r-- | source/Chunk.cpp | 61 | ||||
-rw-r--r-- | source/World.cpp | 209 | ||||
-rw-r--r-- | source/World.h | 5 |
3 files changed, 135 insertions, 140 deletions
diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 1d649f3f6..8c4c77250 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -500,6 +500,67 @@ void cChunk::getRandomBlock(int& a_X, int& a_Y, int& a_Z) void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) { + int Center_X,Center_Y,Center_Z; + getRandomBlock(Center_X,Center_Y,Center_Z); + + BLOCKTYPE PackCenterBlock = GetBlock(Center_X, Center_Y, Center_Z); + if (a_MobSpawner.CheckPackCenter(PackCenterBlock)) + { + a_MobSpawner.NewPack(); + int NumberOfTries = 0; + int NumberOfSuccess = 0; + int MaxNbOfSuccess = 4; // this can be changed during the process for Wolves and Ghass + while (NumberOfTries < 12 && NumberOfSuccess < MaxNbOfSuccess) + { + const int HorizontalRange = 20; // MG TODO : relocate + const int VerticalRange = 0; // MG TODO : relocate + int Try_X, Try_Y, Try_Z; + getThreeRandomNumber(Try_X, Try_Y, Try_Z, 2*HorizontalRange+1 , 2*VerticalRange+1 , 2*HorizontalRange+1); + Try_X -= HorizontalRange; + Try_Y -= VerticalRange; + Try_Z -= HorizontalRange; + Try_X += Center_X; + Try_Y += Center_Y; + Try_Z += Center_Z; + + 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 + + // 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 + cEntity* newMob = a_MobSpawner.TryToSpawnHere(BlockType, BlockMeta, BlockType_below, BlockMeta_below, BlockType_above, BlockMeta_above, Biome, Try_Y, MaxNbOfSuccess); + if (newMob) + { + int WorldX, WorldY, WorldZ; + PositionToWorldPosition(Try_X, Try_Y, Try_Z, WorldX, WorldY, WorldZ); + newMob->SetPosition(WorldX, WorldY, WorldZ); + LOGD("Spawning %s #%i at %d,%d,%d",newMob->GetClass(),newMob->GetUniqueID(),WorldX, WorldY, WorldZ); + NumberOfSuccess++; + } + } + + NumberOfTries++; + } + } + } diff --git a/source/World.cpp b/source/World.cpp index 17c5ccb3e..2e8f30840 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -30,6 +30,9 @@ // Mobs: #include "Mobs/IncludeAllMonsters.h" #include "MobCensus.h" +#include "MobSpawner.h" +#include "MobTypesManager.h" + #include "OSSupport/MakeDir.h" #include "MersenneTwister.h" @@ -226,7 +229,6 @@ cWorld::cWorld(const AString & a_WorldName) : m_WorldAge(0), m_TimeOfDay(0), m_LastTimeUpdate(0), - m_LastSpawnMonster(0), m_RSList(0), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) @@ -490,14 +492,13 @@ void cWorld::Start(void) m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); m_bAnimals = true; - m_SpawnMonsterRate = 200; // 1 mob each 10 seconds - cIniFile IniFile2("settings.ini"); - if (IniFile2.ReadFile()) - { - m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true); - m_SpawnMonsterRate = (Int64)(IniFile2.GetValueF("Monsters", "AnimalSpawnInterval", 10) * 20); // Convert from secs to ticks - - } + + m_AllowedMobs.insert(cMonster::mtCow); // MG TODO : temporary + m_AllowedMobs.insert(cMonster::mtZombie); + m_AllowedMobs.insert(cMonster::mtZombiePigman); + m_AllowedMobs.insert(cMonster::mtBat); + m_AllowedMobs.insert(cMonster::mtSpider); + m_AllowedMobs.insert(cMonster::mtGhast); m_ChunkMap = new cChunkMap(this); @@ -527,6 +528,13 @@ void cWorld::Start(void) m_ChunkSender.Start(this); m_TickThread.Start(); + // Init of the spawn monster time (as they are supposed to have different spawn rate) + m_LastSpawnMonster.insert(std::map<cMonster::eFamily,Int64>::value_type(cMonster::mfHostile,0)); + m_LastSpawnMonster.insert(std::map<cMonster::eFamily,Int64>::value_type(cMonster::mfPassive,0)); + m_LastSpawnMonster.insert(std::map<cMonster::eFamily,Int64>::value_type(cMonster::mfAmbient,0)); + m_LastSpawnMonster.insert(std::map<cMonster::eFamily,Int64>::value_type(cMonster::mfWater,0)); + + // Save any changes that the defaults may have done to the ini file: if (!IniFile.WriteFile()) { @@ -713,104 +721,52 @@ void cWorld::TickMobs(float a_Dt) { return; } -/* + + // before every Mob action, we have to "counts" them depending on the distance to players, on their megatype ... cMobCensus MobCensus; m_ChunkMap->CollectMobCensus(MobCensus); - MobCensus.logd(); - - m_LastSpawnMonster = m_WorldAge; - Vector3d SpawnPos; - { - cCSLock Lock(m_CSPlayers); - if (m_Players.size() <= 0) - { - return; - } - int RandomPlayerIdx = m_TickRand.randInt() & m_Players.size(); - cPlayerList::iterator itr = m_Players.begin(); - for (int i = 1; i < RandomPlayerIdx; i++) - { - itr++; - } - SpawnPos = (*itr)->GetPosition(); - } - - int dayRand = (m_TickRand.randInt() / 7) % 6; - int nightRand = (m_TickRand.randInt() / 11) % 10; - SpawnPos += Vector3d((double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32); - int Height = GetHeight((int)SpawnPos.x, (int)SpawnPos.z); - - int MobType = -1; - int Biome = GetBiomeAt((int)SpawnPos.x, (int)SpawnPos.z); - switch (Biome) + for(cMobFamilyCollecter::tMobFamilyList::const_iterator itr = cMobFamilyCollecter::m_AllFamilies().begin(); itr != cMobFamilyCollecter::m_AllFamilies().end(); itr++) { - case biNether: - { - // Spawn nether mobs - switch (nightRand) - { - case 5: MobType = cMonster::mtGhast; break; - case 6: MobType = cMonster::mtZombiePigman; break; - } - break; - } - - case biEnd: - { - // Only endermen spawn in the End - MobType = cMonster::mtEnderman; - break; - } - - case biMushroomIsland: - case biMushroomShore: - { - // Mushroom land gets only mooshrooms - MobType = cMonster::mtMooshroom; - break; - } - - default: + cMobCensus::tMobSpawnRate::const_iterator spawnrate = cMobCensus::m_SpawnRate().find(*itr); + // hostile mobs are spawned more often + if (spawnrate != cMobCensus::m_SpawnRate().end() && m_LastSpawnMonster[*itr] < m_WorldAge - spawnrate->second) { - // Overworld biomes depend on whether it's night or day: - if (m_TimeOfDay >= 12000 + 1000) + m_LastSpawnMonster[*itr] = m_WorldAge; + // each megatype of mob has it's own cap + if (!(MobCensus.isCaped(*itr))) { - // Night mobs: - switch (nightRand) - { - case 0: MobType = cMonster::mtSpider; break; - case 1: MobType = cMonster::mtZombie; break; - case 2: MobType = cMonster::mtEnderman; break; - case 3: MobType = cMonster::mtCreeper; break; - case 4: MobType = cMonster::mtCaveSpider; break; - case 7: MobType = cMonster::mtSlime; break; - case 8: MobType = cMonster::mtSilverfish; break; - case 9: MobType = cMonster::mtSkeleton; break; - } - } // if (night) - else - { - // During the day: - switch (dayRand) + if (m_bAnimals) { - case 0: MobType = cMonster::mtChicken; break; - case 1: MobType = cMonster::mtCow; break; - case 2: MobType = cMonster::mtPig; break; - case 3: MobType = cMonster::mtSheep; break; - case 4: MobType = cMonster::mtSquid; break; - case 5: MobType = cMonster::mtWolf; break; + cMobSpawner Spawner(*itr,m_AllowedMobs); + if (Spawner.CanSpawnSomething()) + { + m_ChunkMap->SpawnMobs(Spawner); + // do the spawn + + for(cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); itr2++) + { + SpawnMobFinalize(*itr2); + } + } } - } // else (night) - } // case overworld biomes - } // switch (biome) + } + } + } - if (MobType >= 0) + // move close mobs + cMobProximityCounter::sIterablePair allCloseEnoughToMoveMobs = MobCensus.getProximityCounter().getMobWithinThosesDistances(-1,64*16);// MG TODO : deal with this magic number (the 16 is the size of a block) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; itr++) { - // A proper mob type was selected, now spawn the mob: - SpawnMob(SpawnPos.x, SpawnPos.y, SpawnPos.z, (cMonster::eType)MobType); + itr->second.m_Monster.Tick(a_Dt,itr->second.m_Chunk); + } + + // remove too far mobs + cMobProximityCounter::sIterablePair allTooFarMobs = MobCensus.getProximityCounter().getMobWithinThosesDistances(128*16,-1);// MG TODO : deal with this magic number (the 16 is the size of a block) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; itr++) + { + itr->second.m_Monster.Destroy(true); } -*/ } @@ -2578,55 +2534,32 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp { cMonster * Monster = NULL; - int Size = GetTickRandomNumber(2) + 1; // 1 .. 3 - - switch (a_MonsterType) - { - case cMonster::mtBat: Monster = new cBat(); break; - case cMonster::mtBlaze: Monster = new cBlaze(); break; - case cMonster::mtCaveSpider: Monster = new cCavespider(); break; - case cMonster::mtChicken: Monster = new cChicken(); break; - case cMonster::mtCow: Monster = new cCow(); break; - case cMonster::mtCreeper: Monster = new cCreeper(); break; - case cMonster::mtEnderman: Monster = new cEnderman(); break; - case cMonster::mtGhast: Monster = new cGhast(); break; - case cMonster::mtMagmaCube: Monster = new cMagmacube(Size); break; - case cMonster::mtMooshroom: Monster = new cMooshroom(); break; - case cMonster::mtOcelot: Monster = new cOcelot(); break; - case cMonster::mtPig: Monster = new cPig(); break; - case cMonster::mtSheep: Monster = new cSheep(); break; - case cMonster::mtSilverfish: Monster = new cSilverfish(); break; - case cMonster::mtSkeleton: Monster = new cSkeleton(); break; - case cMonster::mtSlime: Monster = new cSlime(Size); break; - case cMonster::mtSpider: Monster = new cSpider(); break; - case cMonster::mtSquid: Monster = new cSquid(); break; - case cMonster::mtVillager: Monster = new cVillager(); break; - case cMonster::mtWitch: Monster = new cWitch(); break; - case cMonster::mtWolf: Monster = new cWolf(); break; - case cMonster::mtZombie: Monster = new cZombie(); break; - case cMonster::mtZombiePigman: Monster = new cZombiepigman(); break; - - default: - { - LOGWARNING("%s: Unhandled monster type: %d. Not spawning.", __FUNCTION__, a_MonsterType); - return -1; - } - } + cMobTypesManager::NewMonsterFromType(a_MonsterType); Monster->SetPosition(a_PosX, a_PosY, a_PosZ); - Monster->SetHealth(Monster->GetMaxHealth()); - if (cPluginManager::Get()->CallHookSpawningMonster(*this, *Monster)) + + return SpawnMobFinalize(Monster); +} + + + + +int cWorld::SpawnMobFinalize(cMonster* a_Monster) +{ + a_Monster->SetHealth(a_Monster->GetMaxHealth()); + if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { - delete Monster; + delete a_Monster; return -1; } - if (!Monster->Initialize(this)) + if (!a_Monster->Initialize(this)) { - delete Monster; + delete a_Monster; return -1; } - BroadcastSpawnEntity(*Monster); - cPluginManager::Get()->CallHookSpawnedMonster(*this, *Monster); - return Monster->GetUniqueID(); + BroadcastSpawnEntity(*a_Monster); + cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster); + + return a_Monster->GetUniqueID(); } diff --git a/source/World.h b/source/World.h index eb19dce40..4590fb9c3 100644 --- a/source/World.h +++ b/source/World.h @@ -574,6 +574,7 @@ public: /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export
+ int SpawnMobFinalize(cMonster* a_Monster);
/// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
@@ -626,7 +627,7 @@ private: Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent.
Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred
Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
- Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned
+ std::map<cMonster::eFamily,Int64> m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned (for each megatype of monster) // MG TODO : find a way to optimize without creating unmaintenability (if mob IDs are becoming unrowed)
eGameMode m_GameMode;
bool m_bEnabledPVP;
@@ -656,7 +657,7 @@ private: cChunkMap * m_ChunkMap;
bool m_bAnimals;
- Int64 m_SpawnMonsterRate;
+ std::set<cMonster::eType> m_AllowedMobs;
eWeather m_Weather;
int m_WeatherInterval;
|