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

330 lines
6.2 KiB
C++
Raw Normal View History

2017-09-19 08:34:08 +00:00
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "BeaconEntity.h"
#include "../BlockArea.h"
2014-07-30 19:59:35 +00:00
#include "../Entities/Player.h"
2014-12-13 14:06:55 +00:00
#include "../UI/BeaconWindow.h"
#include "../ClientHandle.h"
2017-06-15 13:32:33 +00:00
cBeaconEntity::cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World):
Super(a_BlockType, a_BlockMeta, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World),
m_IsActive(false),
m_BeaconLevel(0),
m_PrimaryEffect(cEntityEffect::effNoEffect),
m_SecondaryEffect(cEntityEffect::effNoEffect)
{
2017-06-15 13:32:33 +00:00
ASSERT(a_BlockType == E_BLOCK_BEACON);
2017-08-10 17:11:27 +00:00
if (m_World != nullptr)
{
UpdateBeacon();
}
}
2014-07-30 19:59:35 +00:00
char cBeaconEntity::CalculatePyramidLevel(void)
{
cBlockArea Area;
2014-07-30 19:59:35 +00:00
int MinY = std::max(GetPosY() - 4, 0);
int MaxY = std::max(GetPosY() - 1, 0);
Area.Read(
*m_World,
GetPosX() - 4, GetPosX() + 4,
MinY, MaxY,
GetPosZ() - 4, GetPosZ() + 4,
cBlockArea::baTypes
);
int Layer = 1;
int MiddleXZ = 4;
2014-07-30 19:59:35 +00:00
for (int Y = (Area.GetSizeY() - 1); Y >= 0; Y--)
{
for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++)
{
for (int Z = MiddleXZ - Layer; Z <= (MiddleXZ + Layer); Z++)
{
if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z)))
{
return static_cast<char>(Layer - 1);
}
}
}
2014-04-11 22:13:16 +00:00
Layer++;
}
return static_cast<char>(Layer - 1);
2014-07-30 19:59:35 +00:00
}
bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel)
2014-07-30 19:59:35 +00:00
{
switch (a_Effect)
2014-07-30 19:59:35 +00:00
{
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;
2014-07-30 19:59:35 +00:00
2014-07-31 21:19:05 +00:00
default:
{
2015-05-24 11:56:56 +00:00
LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, static_cast<int>(a_Effect));
2014-07-31 21:19:05 +00:00
return false;
}
}
2014-07-30 19:59:35 +00:00
}
bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect)
2014-07-30 19:59:35 +00:00
{
if (!IsValidEffect(a_Effect, m_BeaconLevel))
2014-07-30 19:59:35 +00:00
{
m_PrimaryEffect = cEntityEffect::effNoEffect;
2014-07-30 19:59:35 +00:00
return false;
}
m_PrimaryEffect = a_Effect;
2014-07-30 20:54:19 +00:00
// Send window update:
2014-10-20 20:55:07 +00:00
if (GetWindow() != nullptr)
2014-07-30 20:54:19 +00:00
{
GetWindow()->SetProperty(1, m_PrimaryEffect);
2014-07-30 20:54:19 +00:00
}
2014-07-30 19:59:35 +00:00
return true;
}
bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect)
2014-07-30 19:59:35 +00:00
{
if (!IsValidEffect(a_Effect, m_BeaconLevel))
2014-07-30 19:59:35 +00:00
{
m_SecondaryEffect = cEntityEffect::effNoEffect;
2014-07-30 19:59:35 +00:00
return false;
}
m_SecondaryEffect = a_Effect;
2014-07-30 20:54:19 +00:00
// Send window update:
2014-10-20 20:55:07 +00:00
if (GetWindow() != nullptr)
2014-07-30 20:54:19 +00:00
{
GetWindow()->SetProperty(2, m_SecondaryEffect);
2014-07-30 20:54:19 +00:00
}
2014-07-30 19:59:35 +00:00
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;
2014-07-30 19:59:35 +00:00
}
}
return false;
}
bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
{
switch (a_BlockType)
{
case E_BLOCK_DIAMOND_BLOCK:
case E_BLOCK_GOLD_BLOCK:
case E_BLOCK_IRON_BLOCK:
case E_BLOCK_EMERALD_BLOCK:
{
return true;
}
}
return false;
}
2014-07-30 19:59:35 +00:00
void cBeaconEntity::UpdateBeacon(void)
{
2014-07-30 20:54:19 +00:00
int OldBeaconLevel = m_BeaconLevel;
2014-07-30 19:59:35 +00:00
if (IsBeaconBlocked())
{
m_IsActive = false;
m_BeaconLevel = 0;
}
else
{
m_BeaconLevel = CalculatePyramidLevel();
m_IsActive = (m_BeaconLevel > 0);
}
if ((m_BeaconLevel != OldBeaconLevel) && (m_BeaconLevel == 4))
2014-07-30 20:54:19 +00:00
{
// Send window update:
2014-10-20 20:55:07 +00:00
if (GetWindow() != nullptr)
2014-07-30 20:54:19 +00:00
{
GetWindow()->SetProperty(0, m_BeaconLevel);
}
Vector3d BeaconPosition(m_PosX, m_PosY, m_PosZ);
GetWorld()->ForEachPlayer([=](cPlayer & a_Player)
{
Vector3d Distance = BeaconPosition - a_Player.GetPosition();
if (
(std::abs(Distance.y) <= 14) &&
(std::abs(Distance.x) <= 20) &&
(std::abs(Distance.z) <= 20)
)
{
a_Player.AwardAchievement(eStatistic::achFullBeacon);
}
return false;
}
);
}
2014-07-30 19:59:35 +00:00
}
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))
2014-07-30 19:59:35 +00:00
{
EffectLevel = 1;
}
cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect;
if ((m_BeaconLevel >= 4) && (m_PrimaryEffect != m_SecondaryEffect) && (m_SecondaryEffect > 0))
2014-07-30 19:59:35 +00:00
{
SecondaryEffect = m_SecondaryEffect;
2014-07-30 19:59:35 +00:00
}
Vector3d BeaconPosition(m_PosX, m_PosY, m_PosZ);
GetWorld()->ForEachPlayer([=](cPlayer & a_Player)
2014-07-30 19:59:35 +00:00
{
auto PlayerPosition = a_Player.GetPosition();
if (PlayerPosition.y > BeaconPosition.y)
2014-10-20 20:55:07 +00:00
{
PlayerPosition.y = BeaconPosition.y;
2014-10-20 20:55:07 +00:00
}
2014-07-30 19:59:35 +00:00
// TODO: Vanilla minecraft uses an AABB check instead of a radius one
if ((PlayerPosition - BeaconPosition).Length() <= Radius)
2014-07-30 19:59:35 +00:00
{
a_Player.AddEntityEffect(m_PrimaryEffect, 180, EffectLevel);
2014-07-30 19:59:35 +00:00
if (m_SecondaryEffect != cEntityEffect::effNoEffect)
2014-07-30 19:59:35 +00:00
{
a_Player.AddEntityEffect(m_SecondaryEffect, 180, 0);
2014-07-30 19:59:35 +00:00
}
}
return false;
}
);
2014-07-30 19:59:35 +00:00
}
2017-06-15 13:32:33 +00:00
void cBeaconEntity::CopyFrom(const cBlockEntity & a_Src)
{
Super::CopyFrom(a_Src);
auto & src = reinterpret_cast<const cBeaconEntity &>(a_Src);
m_BeaconLevel = src.m_BeaconLevel;
m_Contents.CopyFrom(src.m_Contents);
m_IsActive = src.m_IsActive;
m_PrimaryEffect = src.m_PrimaryEffect;
m_SecondaryEffect = src.m_SecondaryEffect;
}
void cBeaconEntity::SendTo(cClientHandle & a_Client)
{
a_Client.SendUpdateBlockEntity(*this);
}
bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
2014-07-30 19:59:35 +00:00
// Update the beacon every 4 seconds
if ((GetWorld()->GetWorldAge() % 80) == 0)
{
UpdateBeacon();
GiveEffects();
}
return false;
}
bool cBeaconEntity::UsedBy(cPlayer * a_Player)
{
2014-07-30 19:59:35 +00:00
cWindow * Window = GetWindow();
2014-10-20 20:55:07 +00:00
if (Window == nullptr)
2014-07-30 19:59:35 +00:00
{
OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
2015-03-10 18:40:53 +00:00
2014-10-20 20:55:07 +00:00
if (Window != nullptr)
2014-07-30 19:59:35 +00:00
{
// 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);
2014-07-30 19:59:35 +00:00
}
}
return true;
}