summaryrefslogtreecommitdiffstats
path: root/src/Entities/Entity.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Entities/Entity.cpp')
-rw-r--r--src/Entities/Entity.cpp194
1 files changed, 193 insertions, 1 deletions
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 8f736a269..334cf5aa7 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -12,6 +12,7 @@
#include "../Bindings/PluginManager.h"
#include "../Tracer.h"
#include "Player.h"
+#include "BlockArea.h"
@@ -629,6 +630,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
// Handle drowning
HandleAir();
}
+ DetectPortal();
// None of the above functions change position, we remain in the chunk of NextChunk
HandlePhysics(a_Dt, *NextChunk);
@@ -868,7 +870,7 @@ void cEntity::TickBurning(cChunk & a_Chunk)
// Remember the current burning state:
bool HasBeenBurning = (m_TicksLeftBurning > 0);
- if (m_World->IsWeatherWet())
+ if (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width, POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width)) || GetWorld()->IsWeatherWet())
{
if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT))
{
@@ -1039,6 +1041,196 @@ void cEntity::DetectCacti(void)
+void cEntity::DetectPortal()
+{
+ if (!GetWorld()->AreNetherPortalsEnabled() && !GetWorld()->AreEndPortalsEnabled())
+ {
+ return;
+ }
+
+ class cPortalChunkLoader : public cChunkStay
+ {
+ public:
+ cPortalChunkLoader(cEntity * a_Entity, Vector3i & a_PortalPos) :
+ m_Entity(a_Entity),
+ m_PortalPos(a_PortalPos)
+ {}
+
+ private:
+ virtual bool OnAllChunksAvailable(void) override
+ {
+ m_Entity->CreateExitPortal(m_PortalPos.x, m_PortalPos.y, m_PortalPos.z);
+ return true;
+ }
+
+ virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override {};
+ virtual void OnDisabled(void) override {};
+
+ cEntity * m_Entity;
+ Vector3i m_PortalPos;
+ };
+
+ int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT;
+ if ((Y > 0) && (Y < cChunkDef::Height))
+ {
+ switch (GetWorld()->GetBlock(X, Y, Z))
+ {
+ case E_BLOCK_NETHER_PORTAL:
+ {
+ if (!GetWorld()->AreNetherPortalsEnabled())
+ {
+ return;
+ }
+
+ switch (GetWorld()->GetDimension())
+ {
+ case dimNether: MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName())); break;
+ case dimOverworld:
+ {
+ if (IsPlayer())
+ {
+ ((cPlayer *)this)->AwardAchievement(achEnterPortal);
+ }
+ MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()));
+
+ cChunkStay * Stay = new cPortalChunkLoader(this, Vector3i(X, Y, Z));
+
+ int MinChunkX, MaxChunkX;
+ int MinChunkZ, MaxChunkZ;
+ cChunkDef::BlockToChunk(X - 128, Z - 128, MinChunkX, MinChunkZ);
+ cChunkDef::BlockToChunk(X + 128, Z + 128, MaxChunkX, MaxChunkZ);
+
+ for (int OtherMinChunkX = MinChunkX; OtherMinChunkX <= MaxChunkX; ++OtherMinChunkX)
+ {
+ for (int OtherMinChunkZ = MinChunkZ; OtherMinChunkZ <= MaxChunkZ; ++OtherMinChunkZ)
+ {
+ Stay->Add(OtherMinChunkX, OtherMinChunkZ);
+ }
+ }
+
+ Stay->Enable(*GetWorld()->GetChunkMap());
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ case E_BLOCK_END_PORTAL:
+ {
+ if (!GetWorld()->AreEndPortalsEnabled())
+ {
+ return;
+ }
+
+ switch (GetWorld()->GetDimension())
+ {
+ case dimEnd:
+ {
+ MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()));
+
+ if (IsPlayer())
+ {
+ cPlayer * Player = (cPlayer *)this;
+ Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z);
+ }
+ break;
+ }
+ case dimOverworld:
+ {
+ if (IsPlayer())
+ {
+ ((cPlayer *)this)->AwardAchievement(achEnterTheEnd);
+ }
+ MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()));
+ break;
+ }
+ default: break;
+ }
+ }
+ default: break;
+ }
+ }
+}
+
+
+
+
+
+void cEntity::CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ cBlockArea Area;
+ Area.Read(GetWorld(), a_BlockX - 128, a_BlockX + 128, 0, 128, a_BlockZ - 128, a_BlockZ + 128);
+ for (int x = a_BlockX - 128; x <= a_BlockX + 128; ++x) for (int y = 0; y <= 128; ++y) for (int z = a_BlockZ - 128; z <= a_BlockZ + 128; ++z)
+ {
+ if (
+ (Area.GetBlockType(x, y, z) == E_BLOCK_NETHER_PORTAL) &&
+ (
+ (Area.GetBlockType(x, (int)floor(y + GetHeight()), z) == E_BLOCK_NETHER_PORTAL) ||
+ (Area.GetBlockType(x, (int)floor(y - GetHeight()), z) == E_BLOCK_NETHER_PORTAL)
+ )
+ )
+ {
+ TeleportToCoords(x, y, z);
+ return;
+ }
+ }
+
+ int MinX = std::max(a_BlockX - (int)ceil(GetWidth()), a_BlockX - 2), MaxX = std::max(a_BlockX + (int)ceil(GetWidth()), a_BlockX + 1);
+ int MinY = std::max(a_BlockY - (int)ceil(GetHeight()), a_BlockY - 2), MaxY = std::max(a_BlockY + (int)ceil(GetHeight()), a_BlockY + 1);
+
+ for (int y = MinY; y < MaxY + 1; y += MaxY - MinY) for (int x = MinX; x < MaxX + 1; ++x)
+ {
+ Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN);
+ }
+ for (int y = MinY; y < MaxY + 1; ++y) for (int x = MinX; x < MaxX + 1; x += MaxX - MinX)
+ {
+ Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN);
+ }
+
+ Area.Write(GetWorld(), MinX, MinY, a_BlockZ);
+}
+
+
+
+
+
+bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World)
+{
+ cWorld * World;
+ if (a_World == NULL)
+ {
+ World = cRoot::Get()->GetWorld(a_WorldName);
+ if (World == NULL)
+ {
+ LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName.c_str());
+ return false;
+ }
+ }
+ else
+ {
+ World = a_World;
+ }
+
+ if (GetWorld() == World)
+ {
+ return false;
+ }
+
+ // Remove all links to the old world
+ GetWorld()->RemoveEntity(this);
+ GetWorld()->BroadcastDestroyEntity(*this);
+
+ // Add to all the necessary parts of the new world
+ SetWorld(World);
+ World->AddEntity(this);
+
+ return true;
+}
+
+
+
+
+
void cEntity::SetSwimState(cChunk & a_Chunk)
{
int RelY = (int)floor(GetPosY() + 0.1);