diff options
Diffstat (limited to 'src/Entities/Entity.cpp')
-rw-r--r-- | src/Entities/Entity.cpp | 194 |
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); |