1
0
Fork 0
cuberite-2a/src/BlockEntities/MobSpawnerEntity.cpp

253 lines
5.2 KiB
C++
Raw Permalink Normal View History

2017-09-19 08:34:08 +00:00
2014-09-17 15:45:13 +00:00
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "MobSpawnerEntity.h"
2014-09-19 21:00:54 +00:00
#include "../World.h"
#include "../FastRandom.h"
#include "../MobSpawner.h"
#include "../ClientHandle.h"
2014-09-19 21:00:54 +00:00
#include "../Items/ItemSpawnEgg.h"
2014-09-17 15:45:13 +00:00
cMobSpawnerEntity::cMobSpawnerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
2020-04-13 16:38:06 +00:00
Super(a_BlockType, a_BlockMeta, a_Pos, a_World),
2017-06-15 13:32:33 +00:00
m_Entity(mtPig),
m_SpawnDelay(100),
m_IsActive(false)
2014-09-17 15:45:13 +00:00
{
2017-06-15 13:32:33 +00:00
ASSERT(a_BlockType == E_BLOCK_MOB_SPAWNER);
}
void cMobSpawnerEntity::CopyFrom(const cBlockEntity & a_Src)
{
2020-04-13 16:38:06 +00:00
Super::CopyFrom(a_Src);
auto & src = static_cast<const cMobSpawnerEntity &>(a_Src);
2017-06-15 13:32:33 +00:00
m_Entity = src.m_Entity;
m_IsActive = src.m_IsActive;
m_SpawnDelay = src.m_SpawnDelay;
m_SpawnCount = src.m_SpawnCount;
m_SpawnRange = src.m_SpawnRange;
m_MinSpawnDelay = src.m_MinSpawnDelay;
m_MaxSpawnDelay = src.m_MaxSpawnDelay;
m_MaxNearbyEntities = src.m_MaxNearbyEntities;
m_RequiredPlayerRange = src.m_RequiredPlayerRange;
2014-09-17 15:45:13 +00:00
}
2014-09-19 21:00:54 +00:00
void cMobSpawnerEntity::SendTo(cClientHandle & a_Client)
2014-09-17 15:45:13 +00:00
{
2014-09-19 21:00:54 +00:00
a_Client.SendUpdateBlockEntity(*this);
2014-09-17 15:45:13 +00:00
}
bool cMobSpawnerEntity::UsedBy(cPlayer * a_Player)
2014-09-19 21:00:54 +00:00
{
if (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SPAWN_EGG)
{
2014-11-18 14:33:41 +00:00
eMonsterType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(a_Player->GetEquippedItem().m_ItemDamage);
if (MonsterType == eMonsterType::mtInvalidType)
2014-09-19 21:00:54 +00:00
{
return false;
2014-09-19 21:00:54 +00:00
}
m_Entity = MonsterType;
ResetTimer();
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
m_World->BroadcastBlockEntity(GetPos());
FLOGD("Changed monster spawner at {0} to type {1}.", GetPos(), cMonster::MobTypeToString(MonsterType));
return true;
2014-09-19 21:00:54 +00:00
}
return false;
2014-09-19 21:00:54 +00:00
}
void cMobSpawnerEntity::UpdateActiveState(void)
2014-09-17 15:45:13 +00:00
{
m_IsActive = (GetNearbyPlayersNum() > 0);
2014-09-17 15:45:13 +00:00
}
bool cMobSpawnerEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
2014-09-17 15:45:13 +00:00
{
using namespace std::chrono_literals;
// Update the active flag every 5 seconds:
if ((m_World->GetWorldTickAge() % 5s) == 0s)
2014-09-19 21:00:54 +00:00
{
UpdateActiveState();
}
if (!m_IsActive)
{
return false;
}
if (m_SpawnDelay <= 0)
2014-09-17 15:45:13 +00:00
{
2014-09-19 21:00:54 +00:00
SpawnEntity();
m_World->BroadcastBlockEntity(GetPos());
2014-09-19 21:00:54 +00:00
return true;
2014-09-17 15:45:13 +00:00
}
else
{
2014-09-19 21:00:54 +00:00
m_SpawnDelay--;
}
return false;
}
void cMobSpawnerEntity::ResetTimer(void)
{
m_SpawnDelay = GetRandomProvider().RandInt<short>(m_MinSpawnDelay, m_MaxSpawnDelay);
2014-09-19 21:00:54 +00:00
}
void cMobSpawnerEntity::SpawnEntity(void)
{
auto NearbyEntities = GetNearbyMonsterNum(m_Entity);
if (NearbyEntities >= m_MaxNearbyEntities)
2014-09-19 21:00:54 +00:00
{
ResetTimer();
return;
}
bool EntitiesSpawned = m_World->DoWithChunk(GetChunkX(), GetChunkZ(), [this, NearbyEntities](cChunk & a_Chunk)
2014-09-19 21:00:54 +00:00
{
2017-06-13 19:35:30 +00:00
auto & Random = GetRandomProvider();
auto EntitySpawnTally = NearbyEntities;
2014-09-19 21:00:54 +00:00
bool HaveSpawnedEntity = false;
for (short I = 0; I < m_SpawnCount; I++)
2014-09-19 21:00:54 +00:00
{
if (EntitySpawnTally >= m_MaxNearbyEntities)
2014-09-19 21:00:54 +00:00
{
break;
}
auto SpawnRelPos(GetRelPos());
SpawnRelPos += Vector3i(
static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * static_cast<double>(m_SpawnRange)),
Random.RandInt(-1, 1),
static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * static_cast<double>(m_SpawnRange))
);
auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(SpawnRelPos);
if ((Chunk == nullptr) || !Chunk->IsValid())
2014-09-19 21:00:54 +00:00
{
continue;
}
EMCSBiome Biome = Chunk->GetBiomeAt(SpawnRelPos.x, SpawnRelPos.z);
2014-09-19 21:00:54 +00:00
if (cMobSpawner::CanSpawnHere(Chunk, SpawnRelPos, m_Entity, Biome, true))
2014-09-19 21:00:54 +00:00
{
auto AbsPos = Chunk->RelativeToAbsolute(SpawnRelPos);
auto Monster = cMonster::NewMonsterFromType(m_Entity);
if (Monster == nullptr)
2014-09-19 21:00:54 +00:00
{
continue;
}
Monster->SetPosition(AbsPos);
Monster->SetYaw(Random.RandReal(360.0f));
if (Chunk->GetWorld()->SpawnMobFinalize(std::move(Monster)) != cEntity::INVALID_ID)
2014-09-19 21:00:54 +00:00
{
HaveSpawnedEntity = true;
m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_MOBSPAWN, AbsPos, 0);
EntitySpawnTally++;
2014-09-19 21:00:54 +00:00
}
}
}
2017-10-02 19:59:25 +00:00
return HaveSpawnedEntity;
2014-09-19 21:00:54 +00:00
}
);
2014-09-19 21:00:54 +00:00
if (EntitiesSpawned)
2014-09-19 21:00:54 +00:00
{
ResetTimer();
2014-09-17 15:45:13 +00:00
}
}
2014-09-19 21:00:54 +00:00
int cMobSpawnerEntity::GetNearbyPlayersNum(void)
{
int NumPlayers = 0;
auto Callback = [this, &NumPlayers](cEntity & a_Entity)
2014-09-19 21:00:54 +00:00
{
if (!a_Entity.IsPlayer())
2014-09-19 21:00:54 +00:00
{
return false;
2014-09-19 21:00:54 +00:00
}
if ((m_Pos - a_Entity.GetPosition()).Length() <= m_RequiredPlayerRange)
2014-09-19 21:00:54 +00:00
{
NumPlayers++;
2014-09-19 21:00:54 +00:00
}
return false;
};
2014-09-19 21:00:54 +00:00
const cBoundingBox PlayerBoundingBox(Vector3d(m_Pos.x, m_Pos.y - m_RequiredPlayerRange, m_Pos.z), m_RequiredPlayerRange, m_RequiredPlayerRange * 2);
m_World->ForEachEntityInBox(PlayerBoundingBox, Callback);
2014-09-19 21:00:54 +00:00
return NumPlayers;
}
2014-09-26 22:07:17 +00:00
int cMobSpawnerEntity::GetNearbyMonsterNum(eMonsterType a_EntityType)
2014-09-19 21:00:54 +00:00
{
int NumEntities = 0;
auto Callback = [this, &NumEntities](cEntity & a_Entity)
2014-09-19 21:00:54 +00:00
{
if (!a_Entity.IsMob())
2014-09-19 21:00:54 +00:00
{
return false;
2014-09-19 21:00:54 +00:00
}
auto & Mob = static_cast<cMonster &>(a_Entity);
if (Mob.GetMobType() == m_Entity)
2014-09-19 21:00:54 +00:00
{
NumEntities++;
2014-09-19 21:00:54 +00:00
}
return false;
};
2014-09-19 21:00:54 +00:00
const cBoundingBox EntityBoundingBox(Vector3d(m_Pos.x, m_Pos.y - 4, m_Pos.z), m_SpawnRange, 8);
m_World->ForEachEntityInBox(EntityBoundingBox, Callback);
2014-09-17 15:45:13 +00:00
2014-09-19 21:00:54 +00:00
return NumEntities;
2014-09-17 15:45:13 +00:00
}