diff options
author | Mattes D <github@xoft.cz> | 2014-08-01 17:43:02 +0200 |
---|---|---|
committer | Mattes D <github@xoft.cz> | 2014-08-01 17:43:02 +0200 |
commit | 35cfbfd51a15233bb0860804c525597d95260300 (patch) | |
tree | b11052934d85badc24e2d17ef1e51b5ea64040ec /src/BlockEntities/BeaconEntity.cpp | |
parent | Merge pull request #1270 from Howaner/Options (diff) | |
parent | Use "default:" in switch. (diff) | |
download | cuberite-35cfbfd51a15233bb0860804c525597d95260300.tar cuberite-35cfbfd51a15233bb0860804c525597d95260300.tar.gz cuberite-35cfbfd51a15233bb0860804c525597d95260300.tar.bz2 cuberite-35cfbfd51a15233bb0860804c525597d95260300.tar.lz cuberite-35cfbfd51a15233bb0860804c525597d95260300.tar.xz cuberite-35cfbfd51a15233bb0860804c525597d95260300.tar.zst cuberite-35cfbfd51a15233bb0860804c525597d95260300.zip |
Diffstat (limited to 'src/BlockEntities/BeaconEntity.cpp')
-rw-r--r-- | src/BlockEntities/BeaconEntity.cpp | 295 |
1 files changed, 276 insertions, 19 deletions
diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 4b9662797..805e5e61f 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -3,33 +3,31 @@ #include "BeaconEntity.h" #include "../BlockArea.h" +#include "../Entities/Player.h" -cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : - super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, a_World) +cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) + : super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World) + , m_IsActive(false) + , m_BeaconLevel(0) + , m_PrimaryEffect(cEntityEffect::effNoEffect) + , m_SecondaryEffect(cEntityEffect::effNoEffect) { + UpdateBeacon(); } -int cBeaconEntity::GetPyramidLevel(void) +char cBeaconEntity::CalculatePyramidLevel(void) { cBlockArea Area; - int MinY = GetPosY() - 4; - if (MinY < 0) - { - MinY = 0; - } - int MaxY = GetPosY() - 1; - if (MaxY < 0) - { - MaxY = 0; - } + int MinY = std::max(GetPosY() - 4, 0); + int MaxY = std::max(GetPosY() - 1, 0); Area.Read( m_World, @@ -42,7 +40,7 @@ int cBeaconEntity::GetPyramidLevel(void) int Layer = 1; int MiddleXZ = 4; - for (int Y = Area.GetSizeY() - 1; Y > 0; Y--) + for (int Y = (Area.GetSizeY() - 1); Y >= 0; Y--) { for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++) { @@ -50,14 +48,97 @@ int cBeaconEntity::GetPyramidLevel(void) { if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z))) { - return Layer - 1; + return (Layer - 1); } } } Layer++; } - return Layer - 1; + return (Layer - 1); +} + + + + + +bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel) +{ + switch (a_Effect) + { + case cEntityEffect::effRegeneration: return (a_BeaconLevel >= 4); + case cEntityEffect::effStrength: return (a_BeaconLevel >= 3); + case cEntityEffect::effResistance: return (a_BeaconLevel >= 2); + case cEntityEffect::effJumpBoost: return (a_BeaconLevel >= 2); + case cEntityEffect::effSpeed: return (a_BeaconLevel >= 1); + case cEntityEffect::effHaste: return (a_BeaconLevel >= 1); + case cEntityEffect::effNoEffect: return true; + + default: + { + LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, (int)a_Effect); + return false; + } + } +} + + + + + +bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect) +{ + if (!IsValidEffect(a_Effect, m_BeaconLevel)) + { + return false; + } + + m_PrimaryEffect = a_Effect; + + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(1, m_PrimaryEffect); + } + return true; +} + + + + + +bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect) +{ + if (!IsValidEffect(a_Effect, m_BeaconLevel)) + { + return false; + } + + m_SecondaryEffect = a_Effect; + + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(2, m_SecondaryEffect); + } + return true; +} + + + + + +bool cBeaconEntity::IsBeaconBlocked(void) +{ + for (int Y = m_PosY; Y < cChunkDef::Height; ++Y) + { + BLOCKTYPE Block = m_World->GetBlock(m_PosX, Y, m_PosZ); + if (!cBlockInfo::IsTransparent(Block)) + { + return true; + } + } + return false; } @@ -83,8 +164,113 @@ bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType) +void cBeaconEntity::UpdateBeacon(void) +{ + int OldBeaconLevel = m_BeaconLevel; + + if (IsBeaconBlocked()) + { + m_IsActive = false; + m_BeaconLevel = 0; + } + else + { + m_BeaconLevel = CalculatePyramidLevel(); + m_IsActive = (m_BeaconLevel > 0); + } + + if (m_BeaconLevel != OldBeaconLevel) + { + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(0, m_BeaconLevel); + } + } + + // TODO: Add achievement +} + + + + + +void cBeaconEntity::GiveEffects(void) +{ + if (!m_IsActive || (m_BeaconLevel < 0)) + { + return; + } + + int Radius = m_BeaconLevel * 10 + 10; + short EffectLevel = 0; + if ((m_BeaconLevel >= 4) && (m_PrimaryEffect == m_SecondaryEffect)) + { + EffectLevel = 1; + } + + cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect; + if ((m_BeaconLevel >= 4) && (m_PrimaryEffect != m_SecondaryEffect) && (m_SecondaryEffect > 0)) + { + SecondaryEffect = m_SecondaryEffect; + } + + class cPlayerCallback : public cPlayerListCallback + { + int m_Radius; + int m_PosX, m_PosY, m_PosZ; + cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect; + short m_EffectLevel; + + virtual bool Item(cPlayer * a_Player) + { + Vector3d PlayerPosition = Vector3d(a_Player->GetPosition()); + if (PlayerPosition.y > (double)m_PosY) + { + PlayerPosition.y = (double)m_PosY; + } + + // TODO: Vanilla minecraft uses an AABB check instead of a radius one + Vector3d BeaconPosition = Vector3d(m_PosX, m_PosY, m_PosZ); + if ((PlayerPosition - BeaconPosition).Length() <= m_Radius) + { + a_Player->AddEntityEffect(m_PrimaryEffect, 180, m_EffectLevel); + + if (m_SecondaryEffect != cEntityEffect::effNoEffect) + { + a_Player->AddEntityEffect(m_SecondaryEffect, 180, 0); + } + } + return false; + } + + public: + cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel) + : m_Radius(a_Radius) + , m_PosX(a_PosX) + , m_PosY(a_PosY) + , m_PosZ(a_PosZ) + , m_PrimaryEffect(a_PrimaryEffect) + , m_SecondaryEffect(a_SecondaryEffect) + , m_EffectLevel(a_EffectLevel) + {}; + + } PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryEffect, SecondaryEffect, EffectLevel); + GetWorld()->ForEachPlayer(PlayerCallback); +} + + + + + bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) { + // Update the beacon every 4 seconds + if ((GetWorld()->GetWorldAge() % 80) == 0) + { + UpdateBeacon(); + GiveEffects(); + } return false; } @@ -92,23 +278,94 @@ bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) -void cBeaconEntity::SaveToJson(Json::Value& a_Value) +void cBeaconEntity::UsedBy(cPlayer * a_Player) { + cWindow * Window = GetWindow(); + if (Window == NULL) + { + OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this)); + Window = GetWindow(); + } + + if (Window != NULL) + { + // if (a_Player->GetWindow() != Window) + // -> Because mojang doesn't send a 'close window' packet when you click the cancel button in the beacon inventory ... + { + a_Player->OpenWindow(Window); + } + } } -void cBeaconEntity::SendTo(cClientHandle & a_Client) + +bool cBeaconEntity::LoadFromJson(const Json::Value & a_Value) +{ + m_PosX = a_Value.get("x", 0).asInt(); + m_PosY = a_Value.get("y", 0).asInt(); + m_PosZ = a_Value.get("z", 0).asInt(); + + Json::Value AllSlots = a_Value.get("Slots", 0); + int SlotIdx = 0; + for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr) + { + cItem Item; + Item.FromJson(*itr); + SetSlot(SlotIdx, Item); + SlotIdx++; + } + + m_BeaconLevel = (char)a_Value.get("Level", 0).asInt(); + int PrimaryEffect = a_Value.get("PrimaryEffect", 0).asInt(); + int SecondaryEffect = a_Value.get("SecondaryEffect", 0).asInt(); + + if ((PrimaryEffect >= 0) && (PrimaryEffect <= (int)cEntityEffect::effSaturation)) + { + m_PrimaryEffect = (cEntityEffect::eType)PrimaryEffect; + } + + if ((SecondaryEffect >= 0) && (SecondaryEffect <= (int)cEntityEffect::effSaturation)) + { + m_SecondaryEffect = (cEntityEffect::eType)SecondaryEffect; + } + + return true; +} + + + + + +void cBeaconEntity::SaveToJson(Json::Value& a_Value) { + a_Value["x"] = m_PosX; + a_Value["y"] = m_PosY; + a_Value["z"] = m_PosZ; + + Json::Value AllSlots; + int NumSlots = m_Contents.GetNumSlots(); + for (int i = 0; i < NumSlots; i++) + { + Json::Value Slot; + m_Contents.GetSlot(i).GetJson(Slot); + AllSlots.append(Slot); + } + a_Value["Slots"] = AllSlots; + + a_Value["Level"] = m_BeaconLevel; + a_Value["PrimaryEffect"] = (int)m_PrimaryEffect; + a_Value["SecondaryEffect"] = (int)m_SecondaryEffect; } -void cBeaconEntity::UsedBy(cPlayer * a_Player) +void cBeaconEntity::SendTo(cClientHandle & a_Client) { + a_Client.SendUpdateBlockEntity(*this); } |