summaryrefslogtreecommitdiffstats
path: root/src/BlockEntities
diff options
context:
space:
mode:
Diffstat (limited to 'src/BlockEntities')
-rw-r--r--src/BlockEntities/BlockEntity.cpp6
-rw-r--r--src/BlockEntities/MobSpawnerEntity.cpp310
-rw-r--r--src/BlockEntities/MobSpawnerEntity.h50
3 files changed, 323 insertions, 43 deletions
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index 05ad03a3d..a969f493e 100644
--- a/src/BlockEntities/BlockEntity.cpp
+++ b/src/BlockEntities/BlockEntity.cpp
@@ -14,10 +14,11 @@
#include "FlowerPotEntity.h"
#include "FurnaceEntity.h"
#include "HopperEntity.h"
+#include "MobHeadEntity.h"
+#include "MobSpawnerEntity.h"
#include "JukeboxEntity.h"
#include "NoteEntity.h"
#include "SignEntity.h"
-#include "MobHeadEntity.h"
@@ -35,8 +36,9 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
- case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
+ case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
+ case E_BLOCK_MOB_SPAWNER: return new cMobSpawnerEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp
index 1db1aad9b..2b963c3f9 100644
--- a/src/BlockEntities/MobSpawnerEntity.cpp
+++ b/src/BlockEntities/MobSpawnerEntity.cpp
@@ -2,22 +2,22 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "MobSpawnerEntity.h"
-#include "../World.h"
#include "json/json.h"
+#include "../World.h"
+#include "../FastRandom.h"
+#include "../MobSpawner.h"
+#include "../Items/ItemSpawnEgg.h"
+
cMobSpawnerEntity::cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World)
: super(E_BLOCK_MOB_SPAWNER, a_BlockX, a_BlockY, a_BlockZ, a_World)
- , m_EntityName("Pig")
- , m_SpawnDelay(20)
- , m_MinSpawnDelay(200)
- , m_MaxSpawnDelay(800)
- , m_MaxNearbyEntities(6)
- , m_ActivatingRange(16)
- , m_SpawnRange(4)
+ , m_Entity(cMonster::mtPig)
+ , m_SpawnDelay(100)
+ , m_IsActive(false)
{
}
@@ -25,37 +25,170 @@ cMobSpawnerEntity::cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c
-cMobSpawnerEntity::~cMobSpawnerEntity()
+void cMobSpawnerEntity::SendTo(cClientHandle & a_Client)
{
-
+ a_Client.SendUpdateBlockEntity(*this);
}
-bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk)
+void cMobSpawnerEntity::UsedBy(cPlayer * a_Player)
+{
+ if (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SPAWN_EGG)
+ {
+ cMonster::eType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(a_Player->GetEquippedItem().m_ItemDamage);
+ if (MonsterType == cMonster::mtInvalidType)
+ {
+ return;
+ }
+
+ m_Entity = MonsterType;
+ ResetTimer();
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ LOGD("Changed monster spawner entity to %s!", GetEntityName().c_str());
+ }
+}
+
+
+
+
+
+void cMobSpawnerEntity::UpdateActiveState(void)
{
-
+ if (GetNearbyPlayersNum() > 0)
+ {
+ m_IsActive = true;
+ }
+ else
+ {
+ m_IsActive = false;
+ }
}
-void cMobSpawnerEntity::UsedBy(cPlayer * a_Player)
+bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
- if (IsPlayingRecord())
+ // Update the active flag every 5 seconds
+ if ((m_World->GetWorldAge() % 100) == 0)
+ {
+ UpdateActiveState();
+ }
+
+ if (!m_IsActive)
+ {
+ return false;
+ }
+
+ if (m_SpawnDelay <= 0)
{
- EjectRecord();
+ SpawnEntity();
+ return true;
}
else
{
- const cItem & HeldItem = a_Player->GetEquippedItem();
- if (PlayRecord(HeldItem.m_ItemType))
+ m_SpawnDelay--;
+ }
+ return false;
+}
+
+
+
+
+
+void cMobSpawnerEntity::ResetTimer(void)
+{
+ m_SpawnDelay = 200 + m_World->GetTickRandomNumber(600);
+ m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ);
+}
+
+
+
+
+
+void cMobSpawnerEntity::SpawnEntity(void)
+{
+ int NearbyEntities = GetNearbyEntityNum(m_Entity);
+ if (NearbyEntities >= 6)
+ {
+ ResetTimer();
+ return;
+ }
+
+ class cCallback : public cChunkCallback
+ {
+ public:
+ cCallback(int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, int a_NearbyEntitiesNum) :
+ m_RelX(a_RelX),
+ m_RelY(a_RelY),
+ m_RelZ(a_RelZ),
+ m_MobType(a_MobType),
+ m_NearbyEntitiesNum(a_NearbyEntitiesNum)
{
- a_Player->GetInventory().RemoveOneEquippedItem();
}
+
+ virtual bool Item(cChunk * a_Chunk)
+ {
+ cFastRandom Random;
+
+ bool EntitiesSpawned = false;
+ for (size_t i = 0; i < 4; i++)
+ {
+ if (m_NearbyEntitiesNum >= 6)
+ {
+ break;
+ }
+
+ int RelX = (int) (m_RelX + (double)(Random.NextFloat() - Random.NextFloat()) * 4.0);
+ int RelY = m_RelY + Random.NextInt(3) - 1;
+ int RelZ = (int) (m_RelZ + (double)(Random.NextFloat() - Random.NextFloat()) * 4.0);
+
+ cChunk * Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(RelX, RelZ);
+ if ((Chunk == NULL) || !Chunk->IsValid())
+ {
+ continue;
+ }
+ EMCSBiome Biome = Chunk->GetBiomeAt(RelX, RelZ);
+
+ if (cMobSpawner::CanSpawnHere(Chunk, RelX, RelY, RelZ, m_MobType, Biome))
+ {
+ double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX;
+ double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ;
+
+ cMonster * Monster = cMonster::NewMonsterFromType(m_MobType);
+ if (Monster == NULL)
+ {
+ continue;
+ }
+
+ Monster->SetPosition(PosX, RelY, PosZ);
+ Monster->SetYaw(Random.NextFloat() * 360.0f);
+ if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cMonster::mtInvalidType)
+ {
+ EntitiesSpawned = true;
+ Chunk->BroadcastSoundParticleEffect(2004, (int)(PosX * 8.0), (int)(RelY * 8.0), (int)(PosZ * 8.0), 0);
+ m_NearbyEntitiesNum++;
+ }
+ }
+ }
+ return EntitiesSpawned;
+ }
+ protected:
+ int m_RelX, m_RelY, m_RelZ;
+ cMonster::eType m_MobType;
+ int m_NearbyEntitiesNum;
+ } Callback(m_RelX, m_PosY, m_RelZ, m_Entity, NearbyEntities);
+
+ if (m_World->DoWithChunk(GetChunkX(), GetChunkZ(), Callback))
+ {
+ ResetTimer();
}
}
@@ -69,8 +202,6 @@ bool cMobSpawnerEntity::LoadFromJson(const Json::Value & a_Value)
m_PosY = a_Value.get("y", 0).asInt();
m_PosZ = a_Value.get("z", 0).asInt();
- m_Record = a_Value.get("Record", 0).asInt();
-
return true;
}
@@ -83,8 +214,145 @@ void cMobSpawnerEntity::SaveToJson(Json::Value & a_Value)
a_Value["x"] = m_PosX;
a_Value["y"] = m_PosY;
a_Value["z"] = m_PosZ;
+}
+
+
+
+
+
+AString cMobSpawnerEntity::GetEntityName() const
+{
+ switch (m_Entity)
+ {
+ case cMonster::mtBat: return "Bat";
+ case cMonster::mtBlaze: return "Blaze";
+ case cMonster::mtCaveSpider: return "CaveSpider";
+ case cMonster::mtChicken: return "Chicken";
+ case cMonster::mtCow: return "Cow";
+ case cMonster::mtCreeper: return "Creeper";
+ case cMonster::mtEnderDragon: return "EnderDragon";
+ case cMonster::mtEnderman: return "Enderman";
+ case cMonster::mtGhast: return "Ghast";
+ case cMonster::mtGiant: return "Giant";
+ case cMonster::mtHorse: return "EntityHorse";
+ case cMonster::mtIronGolem: return "VillagerGolem";
+ case cMonster::mtMagmaCube: return "LavaSlime";
+ case cMonster::mtMooshroom: return "MushroomCow";
+ case cMonster::mtOcelot: return "Ozelot";
+ case cMonster::mtPig: return "Pig";
+ case cMonster::mtSheep: return "Sheep";
+ case cMonster::mtSilverfish: return "Silverfish";
+ case cMonster::mtSkeleton: return "Skeleton";
+ case cMonster::mtSlime: return "Slime";
+ case cMonster::mtSnowGolem: return "SnowMan";
+ case cMonster::mtSpider: return "Spider";
+ case cMonster::mtSquid: return "Squid";
+ case cMonster::mtVillager: return "Villager";
+ case cMonster::mtWitch: return "Witch";
+ case cMonster::mtWither: return "WitherBoss";
+ case cMonster::mtWolf: return "Wolf";
+ case cMonster::mtZombie: return "Zombie";
+ case cMonster::mtZombiePigman: return "PigZombie";
+ default:
+ {
+ ASSERT(!"Unknown monster type!");
+ return "Pig";
+ }
+ }
+}
+
+
+
+
+
+int cMobSpawnerEntity::GetNearbyPlayersNum(void)
+{
+ Vector3d SpawnerPos(m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
+ int NumPlayers = 0;
+
+ class cCallback : public cChunkDataCallback
+ {
+ public:
+ cCallback(Vector3d a_SpawnerPos, int & a_NumPlayers) :
+ m_SpawnerPos(a_SpawnerPos),
+ m_NumPlayers(a_NumPlayers)
+ {
+ }
+
+ virtual void Entity(cEntity * a_Entity) override
+ {
+ if (!a_Entity->IsPlayer())
+ {
+ return;
+ }
+
+ if ((m_SpawnerPos - a_Entity->GetPosition()).Length() <= 16)
+ {
+ m_NumPlayers++;
+ }
+ }
+
+ protected:
+ Vector3d m_SpawnerPos;
+ int & m_NumPlayers;
+ } Callback(SpawnerPos, NumPlayers);
+
+ int ChunkX = GetChunkX();
+ int ChunkZ = GetChunkZ();
+ m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback);
+
+ return NumPlayers;
+}
+
+
+
+
+
+int cMobSpawnerEntity::GetNearbyEntityNum(cMonster::eType a_EntityType)
+{
+ Vector3d SpawnerPos(m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
+ int NumEntities = 0;
+
+ class cCallback : public cChunkDataCallback
+ {
+ public:
+ cCallback(Vector3d a_SpawnerPos, cMonster::eType a_EntityType, int & a_NumEntities) :
+ m_SpawnerPos(a_SpawnerPos),
+ m_EntityType(a_EntityType),
+ m_NumEntities(a_NumEntities)
+ {
+ }
+
+ virtual void Entity(cEntity * a_Entity) override
+ {
+ if (!a_Entity->IsMob())
+ {
+ return;
+ }
+
+ cMonster * Mob = (cMonster *)a_Entity;
+ if (Mob->GetMobType() != m_EntityType)
+ {
+ return;
+ }
+
+ if (((m_SpawnerPos - a_Entity->GetPosition()).Length() <= 8) && (Diff(m_SpawnerPos.y, a_Entity->GetPosY()) <= 4.0))
+ {
+ m_NumEntities++;
+ }
+ }
+
+ protected:
+ Vector3d m_SpawnerPos;
+ cMonster::eType m_EntityType;
+ int & m_NumEntities;
+ } Callback(SpawnerPos, a_EntityType, NumEntities);
+
+ int ChunkX = GetChunkX();
+ int ChunkZ = GetChunkZ();
+ m_World->ForEachChunkInRect(ChunkX - 1, ChunkX + 1, ChunkZ - 1, ChunkZ + 1, Callback);
- a_Value["Record"] = m_Record;
+ return NumEntities;
}
diff --git a/src/BlockEntities/MobSpawnerEntity.h b/src/BlockEntities/MobSpawnerEntity.h
index b173214a5..b12a97d65 100644
--- a/src/BlockEntities/MobSpawnerEntity.h
+++ b/src/BlockEntities/MobSpawnerEntity.h
@@ -28,41 +28,51 @@ public:
// tolua_end
cMobSpawnerEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
- virtual ~cMobSpawnerEntity();
-
- bool LoadFromJson(const Json::Value & a_Value);
- virtual void SaveToJson(Json::Value & a_Value) override;
+ virtual void SendTo(cClientHandle & a_Client) override;
+ virtual void UsedBy(cPlayer * a_Player) override;
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
// tolua_begin
- /** Returns the entity who will be spawn by this mob spawner. */
- const AString & GetEntityName(void) const { return m_EntityName; }
+ /** Upate the active flag from the mob spawner. This function will called every 5 seconds from the Tick() function. */
+ void UpdateActiveState(void);
+
+ /** Sets the spawn delay to a new random value. */
+ void ResetTimer(void);
+
+ /** Spawns the entity. This function automaticly change the spawn delay! */
+ void SpawnEntity(void);
+
+ /** Returns the entity type who will be spawn by this mob spawner. */
+ cMonster::eType GetEntity(void) const { return m_Entity; }
+
+ /** Sets the entity type who will be spawn by this mob spawner. */
+ void SetEntity(cMonster::eType a_EntityType) { m_Entity = a_EntityType; }
+
+ /** Returns the entity name. (Required by the protocol) */
+ AString GetEntityName(void) const;
+
+ /** Returns the spawn delay. */
+ int GetSpawnDelay(void) const { return m_SpawnDelay; }
+
+ int GetNearbyPlayersNum(void);
+ int GetNearbyEntityNum(cMonster::eType a_EntityType);
// tolua_end
+ bool LoadFromJson(const Json::Value & a_Value);
+ virtual void SaveToJson(Json::Value & a_Value) override;
+
static const char * GetClassStatic(void) { return "cMobSpawnerEntity"; }
-
- virtual void UsedBy(cPlayer * a_Player) override;
- virtual void SendTo(cClientHandle &) override {}
private:
/** The entity to spawn. */
- AString m_EntityName;
+ cMonster::eType m_Entity;
int m_SpawnDelay;
- int m_MinSpawnDelay;
- int m_MaxSpawnDelay;
-
- /** The mob spawner spawns only mobs when the count of nearby entities (without players) is lesser than this number. */
- short m_MaxNearbyEntities;
-
- /** The mob spawner spawns only mobs when a player is in the range of the mob spawner. */
- short m_ActivatingRange;
- /** The range coefficient for spawning entities around. */
- short m_SpawnRange;
+ bool m_IsActive;
} ; // tolua_end