aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/MobSpawner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.World/MobSpawner.cpp')
-rw-r--r--Minecraft.World/MobSpawner.cpp191
1 files changed, 18 insertions, 173 deletions
diff --git a/Minecraft.World/MobSpawner.cpp b/Minecraft.World/MobSpawner.cpp
index d2b4f6fd..8cd60e92 100644
--- a/Minecraft.World/MobSpawner.cpp
+++ b/Minecraft.World/MobSpawner.cpp
@@ -39,7 +39,7 @@ TilePos MobSpawner::getRandomPosWithin(Level *level, int cx, int cz)
unordered_map<ChunkPos,bool,ChunkPosKeyHash,ChunkPosKeyEq> MobSpawner::chunksToPoll;
#endif
-const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies)
+const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies, bool spawnPersistent)
{
#ifndef _CONTENT_PACKAGE
@@ -94,7 +94,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
#endif
#endif
- if (!spawnEnemies && !spawnFriendlies)
+ if (!spawnEnemies && !spawnFriendlies && !spawnPersistent)
{
return 0;
}
@@ -193,15 +193,24 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
MemSect(31);
Pos *spawnPos = level->getSharedSpawnPos();
MemSect(0);
-
+
for (unsigned int i = 0; i < MobCategory::values.length; i++)
{
MobCategory *mobCategory = MobCategory::values[i];
- if ((mobCategory->isFriendly() && !spawnFriendlies) || (!mobCategory->isFriendly() && !spawnEnemies))
+ if ((mobCategory->isFriendly() && !spawnFriendlies) || (!mobCategory->isFriendly() && !spawnEnemies) || (mobCategory->isPersistent() && !spawnPersistent))
{
continue;
}
+ // 4J - early out for non-main dimensions, if spawning anything friendly
+ if( mobCategory->isFriendly() )
+ {
+ if( level->dimension->id != 0 )
+ {
+ continue;
+ }
+ }
+
// 4J - this is now quite different to the java version. We just have global max counts for the level whereas the original has a max per chunk that
// scales with the number of chunks to be polled.
int categoryCount = level->countInstanceOf( mobCategory->getEnumBaseClass(), mobCategory->isSingleType());
@@ -221,8 +230,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
#endif
if( it->second )
{
- // don't add mobs to edge chunks, to prevent adding mobs
- // "outside" of the active playground
+ // don't add mobs to edge chunks, to prevent adding mobs "outside" of the active playground
continue;
}
ChunkPos *cp = (ChunkPos *) (&it->first);
@@ -247,6 +255,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
int ss = 6;
Biome::MobSpawnerData *currentMobType = NULL;
+ MobGroupData *groupData = NULL;
for (int ll = 0; ll < 4; ll++)
{
@@ -349,8 +358,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
categoryCount++;
mob->setDespawnProtected(); // 4J added - default to protected against despawning
level->addEntity(mob);
- finalizeMobSettings(mob, level, xx, yy, zz);
- mob->finalizeMobSpawn();
+ groupData = mob->finalizeMobSpawn(groupData);
// 4J - change here so that we can't ever make more than the desired amount of entities in each priority. In the original java version
// depending on the random spawn positions being considered the only limit as to the number of entities created per category is the number
// of chunks to poll.
@@ -420,171 +428,7 @@ bool MobSpawner::isSpawnPositionOk(MobCategory *category, Level *level, int x, i
int tt = level->getTile(x, y - 1, z);
return tt != Tile::unbreakable_Id && !level->isSolidBlockingTile(x, y, z) && !level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z);
}
-}
-
-
-void MobSpawner::finalizeMobSettings(shared_ptr<Mob> mob, Level *level, float xx, float yy, float zz)
-{
- if (dynamic_pointer_cast<Spider>( mob ) != NULL && level->random->nextInt(100) == 0)
- {
- shared_ptr<Skeleton> skeleton = shared_ptr<Skeleton>( new Skeleton(level) );
- skeleton->moveTo(xx, yy, zz, mob->yRot, 0);
- level->addEntity(skeleton);
- skeleton->ride(mob);
- }
- else if (dynamic_pointer_cast<Sheep >( mob ) != NULL)
- {
- (dynamic_pointer_cast<Sheep>( mob ))->setColor(Sheep::getSheepColor(level->random));
- }
- else if (dynamic_pointer_cast<Ozelot >( mob ) != NULL)
- {
- if (level->random->nextInt(7) == 0)
- {
- for (int kitten = 0; kitten < 2; kitten++)
- {
- shared_ptr<Ozelot> ozelot = shared_ptr<Ozelot>(new Ozelot(level));
- ozelot->moveTo(xx, yy, zz, mob->yRot, 0);
- ozelot->setAge(-20 * 60 * 20);
- level->addEntity(ozelot);
- }
- }
- }
-}
-
-
-// 4J Stu TODO This was an array of Class type. I haven't made a base Class type yet, but don't need to
-// as this can be an array of Mob type?
-eINSTANCEOF MobSpawner::bedEnemies[bedEnemyCount] = {
- eTYPE_SPIDER, eTYPE_ZOMBIE, eTYPE_SKELETON
-};
-
-
-bool MobSpawner::attackSleepingPlayers(Level *level, vector<shared_ptr<Player> > *players)
-{
-
- bool somebodyWokeUp = false;
-
- PathFinder finder = PathFinder(level, true, false, false, true);
-
- AUTO_VAR(itEnd, players->end());
- for (AUTO_VAR(it, players->begin()); it != itEnd; it++)
- {
- shared_ptr<Player> player = (*it);
-
- bool nextPlayer = false;
-
- for (int attemptCount = 0; attemptCount < 20 && !nextPlayer; attemptCount++)\
- {
-
-
- // limit position within the range of the player
- int x = Mth::floor(player->x) + level->random->nextInt(32) - level->random->nextInt(32);
- int z = Mth::floor(player->z) + level->random->nextInt(32) - level->random->nextInt(32);
- int yStart = Mth::floor(player->y) + level->random->nextInt(16) - level->random->nextInt(16);
- if (yStart < 1)
- {
- yStart = 1;
- }
- else if (yStart > Level::maxBuildHeight)
- {
- yStart = Level::maxBuildHeight;
- }
-
- {
- int type = level->random->nextInt(bedEnemyCount);
- int y = yStart;
-
- while (y > 2 && !level->isTopSolidBlocking(x, y - 1, z))
- {
- y--;
- }
-
- while (!isSpawnPositionOk( (MobCategory *) MobCategory::monster, level, x, y, z) && y < (yStart + 16) && y < Level::maxBuildHeight)
- {
- y++;
- }
- if (y >= (yStart + 16) || y >= Level::maxBuildHeight)
- {
- y = yStart;
- continue;
}
- else
- {
- float xx = x + 0.5f;
- float yy = (float) y;
- float zz = z + 0.5f;
-
- shared_ptr<Mob> mob;
-// 4J - removed try/catch
-// try
-// {
- //mob = classes[type].getConstructor(Level.class).newInstance(level);
- // 4J - there was a classes array here which duplicated the bedEnemies array but have removed it
- mob = dynamic_pointer_cast<Mob>(EntityIO::newByEnumType(bedEnemies[type], level ));
-// }
-// catch (exception e)
-// {
-// // TODO 4J Stu - We can't print a stack trace, and newInstance doesn't currently throw an exception anyway
-// //e.printStackTrace();
-// return somebodyWokeUp;
-// }
-
- // System.out.println("Placing night mob");
- mob->moveTo(xx, yy, zz, level->random->nextFloat() * 360, 0);
- // check if the mob can spawn at this location
- if (!mob->canSpawn())
- {
- continue;
- }
- Pos *bedPos = BedTile::findStandUpPosition(level, Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z), 1);
- if (bedPos == NULL)
- {
- // an unlikely case where the bed is
- // completely blocked
- bedPos = new Pos(x, y + 1, z);
- }
-
- // 4J Stu - TU-1 hotfix
- // Fix for #13152 - If the player sleeps in a bed next to a wall in an enclosed, well lit area they will be awoken by a monster
- // The pathfinder should attempt to get close to the position that we will move the mob to,
- // instead of the player who could be next to a wall. Otherwise the paths gets to the other
- // side of the the wall, then moves the mob inside the building
- //Path *findPath = finder.findPath(mob.get(), player.get(), 32.0f);
- Path *findPath = finder.findPath(mob.get(), bedPos->x, bedPos->y, bedPos->z, 32.0f);
- if (findPath != NULL && findPath->getSize() > 1)
- {
- Node *last = findPath->last();
-
- if (abs(last->x - bedPos->x) < 1.5 && abs(last->z - bedPos->z) < 1.5 && abs(last->y - bedPos->y) < 1.5)
- {
- // System.out.println("Found path!");
-
- mob->moveTo(bedPos->x + 0.5f, bedPos->y, bedPos->z + 0.5f, 0, 0);
- // the mob would maybe not be able to
- // spawn here, but we ignore that now (we assume
- // it walked here)
- {
- level->addEntity(mob);
- finalizeMobSettings(mob, level, bedPos->x + 0.5f, (float) bedPos->y, bedPos->z + 0.5f);
- mob->finalizeMobSpawn();
- player->stopSleepInBed(true, false, false);
- // play a sound effect to scare the player
- mob->playAmbientSound();
- somebodyWokeUp = true;
- nextPlayer = true;
- }
- }
- delete findPath;
- }
- delete bedPos;
- }
- }
- }
- }
-
-
- return somebodyWokeUp;
-}
void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo, int cellWidth, int cellHeight, Random *random)
{
@@ -599,6 +443,7 @@ void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo
while (random->nextFloat() < biome->getCreatureProbability())
{
Biome::MobSpawnerData *type = (Biome::MobSpawnerData *) WeighedRandom::getRandomItem(level->random, ((vector<WeighedRandomItem *> *)mobs));
+ MobGroupData *groupData = NULL;
int count = type->minCount + random->nextInt(1 + type->maxCount - type->minCount);
int x = xo + random->nextInt(cellWidth);
@@ -633,7 +478,7 @@ void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo
mob->setDespawnProtected();
level->addEntity(mob);
- finalizeMobSettings(mob, level, xx, yy, zz);
+ groupData = mob->finalizeMobSpawn(groupData);
success = true;
}