2017-09-19 08:34:08 +00:00
|
|
|
|
2014-04-11 22:01:15 +00:00
|
|
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
|
|
|
|
|
|
|
#include "BeaconEntity.h"
|
2020-04-03 06:57:01 +00:00
|
|
|
#include "../BlockInfo.h"
|
2014-04-11 22:01:15 +00:00
|
|
|
#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"
|
2016-11-18 19:00:04 +00:00
|
|
|
#include "../ClientHandle.h"
|
2014-04-11 22:01:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-09-29 12:59:24 +00:00
|
|
|
cBeaconEntity::cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
|
2020-04-13 16:38:06 +00:00
|
|
|
Super(a_BlockType, a_BlockMeta, a_Pos, 1, 1, a_World),
|
2016-11-18 19:00:04 +00:00
|
|
|
m_IsActive(false),
|
|
|
|
m_BeaconLevel(0),
|
|
|
|
m_PrimaryEffect(cEntityEffect::effNoEffect),
|
|
|
|
m_SecondaryEffect(cEntityEffect::effNoEffect)
|
2014-04-11 22:01:15 +00:00
|
|
|
{
|
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-04-11 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-30 19:59:35 +00:00
|
|
|
char cBeaconEntity::CalculatePyramidLevel(void)
|
2014-04-11 22:01:15 +00:00
|
|
|
{
|
|
|
|
cBlockArea Area;
|
2014-07-30 19:59:35 +00:00
|
|
|
int MinY = std::max(GetPosY() - 4, 0);
|
|
|
|
int MaxY = std::max(GetPosY() - 1, 0);
|
2014-04-11 22:35:13 +00:00
|
|
|
|
2014-04-11 22:01:15 +00:00
|
|
|
Area.Read(
|
2017-02-05 15:00:38 +00:00
|
|
|
*m_World,
|
2014-04-19 11:05:58 +00:00
|
|
|
GetPosX() - 4, GetPosX() + 4,
|
|
|
|
MinY, MaxY,
|
|
|
|
GetPosZ() - 4, GetPosZ() + 4,
|
2014-04-11 22:35:13 +00:00
|
|
|
cBlockArea::baTypes
|
2014-04-11 22:01:15 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
int Layer = 1;
|
|
|
|
int MiddleXZ = 4;
|
|
|
|
|
2014-07-30 19:59:35 +00:00
|
|
|
for (int Y = (Area.GetSizeY() - 1); Y >= 0; Y--)
|
2014-04-11 22:01:15 +00:00
|
|
|
{
|
|
|
|
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)))
|
|
|
|
{
|
2015-07-29 15:04:03 +00:00
|
|
|
return static_cast<char>(Layer - 1);
|
2014-04-11 22:01:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-11 22:13:16 +00:00
|
|
|
Layer++;
|
2014-04-11 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
2015-07-29 15:04:03 +00:00
|
|
|
return static_cast<char>(Layer - 1);
|
2014-07-30 19:59:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-31 10:13:11 +00:00
|
|
|
bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel)
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
2014-07-31 16:15:39 +00:00
|
|
|
switch (a_Effect)
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
2014-07-31 16:15:39 +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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-31 16:15:39 +00:00
|
|
|
bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect)
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
2014-07-31 10:13:11 +00:00
|
|
|
if (!IsValidEffect(a_Effect, m_BeaconLevel))
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
2014-08-01 22:14:05 +00:00
|
|
|
m_PrimaryEffect = cEntityEffect::effNoEffect;
|
2014-07-30 19:59:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-31 10:13:11 +00:00
|
|
|
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
|
|
|
{
|
2014-07-31 10:13:11 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-31 16:15:39 +00:00
|
|
|
bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect)
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
2014-07-31 10:13:11 +00:00
|
|
|
if (!IsValidEffect(a_Effect, m_BeaconLevel))
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
2014-08-01 22:14:05 +00:00
|
|
|
m_SecondaryEffect = cEntityEffect::effNoEffect;
|
2014-07-30 19:59:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-31 10:13:11 +00:00
|
|
|
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
|
|
|
{
|
2014-07-31 10:13:11 +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)
|
|
|
|
{
|
2019-09-29 12:59:24 +00:00
|
|
|
for (int Y = m_Pos.y; Y < cChunkDef::Height; ++Y)
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
2019-09-29 12:59:24 +00:00
|
|
|
BLOCKTYPE Block = m_World->GetBlock({m_Pos.x, Y, m_Pos.z});
|
2014-07-30 19:59:35 +00:00
|
|
|
if (!cBlockInfo::IsTransparent(Block))
|
|
|
|
{
|
2014-07-31 10:13:11 +00:00
|
|
|
return true;
|
2014-07-30 19:59:35 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-31 10:13:11 +00:00
|
|
|
return false;
|
2014-04-11 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
|
|
|
|
{
|
2014-07-21 13:19:48 +00:00
|
|
|
switch (a_BlockType)
|
2014-04-11 22:01:15 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-08-21 14:00:49 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-09-29 12:59:24 +00:00
|
|
|
Vector3d BeaconPosition(m_Pos);
|
2017-09-11 21:20:49 +00:00
|
|
|
GetWorld()->ForEachPlayer([=](cPlayer & a_Player)
|
2017-08-21 14:00:49 +00:00
|
|
|
{
|
2017-09-11 21:20:49 +00:00
|
|
|
Vector3d Distance = BeaconPosition - a_Player.GetPosition();
|
2017-08-21 14:00:49 +00:00
|
|
|
if (
|
|
|
|
(std::abs(Distance.y) <= 14) &&
|
|
|
|
(std::abs(Distance.x) <= 20) &&
|
|
|
|
(std::abs(Distance.z) <= 20)
|
|
|
|
)
|
|
|
|
{
|
2020-08-12 08:54:36 +00:00
|
|
|
a_Player.AwardAchievement(Statistic::AchFullBeacon);
|
2017-08-21 14:00:49 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-09-11 21:20:49 +00:00
|
|
|
);
|
2017-08-21 14:00:49 +00:00
|
|
|
}
|
2014-07-30 19:59:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cBeaconEntity::GiveEffects(void)
|
|
|
|
{
|
|
|
|
if (!m_IsActive || (m_BeaconLevel < 0))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-09 19:19:22 +00:00
|
|
|
double Radius = static_cast<double>(m_BeaconLevel) * 10 + 10;
|
2014-07-30 19:59:35 +00:00
|
|
|
short EffectLevel = 0;
|
2014-07-31 10:13:11 +00:00
|
|
|
if ((m_BeaconLevel >= 4) && (m_PrimaryEffect == m_SecondaryEffect))
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
|
|
|
EffectLevel = 1;
|
|
|
|
}
|
|
|
|
|
2017-10-02 19:59:25 +00:00
|
|
|
bool HasSecondaryEffect = (m_BeaconLevel >= 4) && (m_PrimaryEffect != m_SecondaryEffect) && (m_SecondaryEffect > 0);
|
2014-07-30 19:59:35 +00:00
|
|
|
|
2020-10-09 19:19:22 +00:00
|
|
|
auto Area = cBoundingBox(m_Pos, Radius, Radius + static_cast<double>(cChunkDef::Height), -Radius);
|
|
|
|
GetWorld()->ForEachEntityInBox(Area, [&](cEntity & a_Entity)
|
|
|
|
{
|
|
|
|
if (!a_Entity.IsPlayer())
|
2014-07-30 19:59:35 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2020-10-09 19:19:22 +00:00
|
|
|
auto & Player = static_cast<cPlayer &>(a_Entity);
|
|
|
|
Player.AddEntityEffect(m_PrimaryEffect, 180, EffectLevel);
|
|
|
|
|
|
|
|
if (HasSecondaryEffect)
|
|
|
|
{
|
|
|
|
Player.AddEntityEffect(m_SecondaryEffect, 180, 0);
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2020-04-13 16:38:06 +00:00
|
|
|
Super::CopyFrom(a_Src);
|
2018-05-02 07:50:36 +00:00
|
|
|
auto & src = static_cast<const cBeaconEntity &>(a_Src);
|
2017-06-15 13:32:33 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-01-11 21:12:26 +00:00
|
|
|
bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
2014-04-11 22:01:15 +00:00
|
|
|
{
|
2014-07-30 19:59:35 +00:00
|
|
|
// Update the beacon every 4 seconds
|
|
|
|
if ((GetWorld()->GetWorldAge() % 80) == 0)
|
|
|
|
{
|
|
|
|
UpdateBeacon();
|
|
|
|
GiveEffects();
|
|
|
|
}
|
2014-04-11 22:01:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-01 22:12:44 +00:00
|
|
|
bool cBeaconEntity::UsedBy(cPlayer * a_Player)
|
2014-04-11 22:01:15 +00:00
|
|
|
{
|
2020-09-05 15:13:44 +00:00
|
|
|
a_Player->GetStatManager().AddValue(Statistic::InteractWithBeacon);
|
|
|
|
|
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
|
|
|
{
|
2019-09-29 12:59:24 +00:00
|
|
|
OpenWindow(new cBeaconWindow(this));
|
2014-07-30 19:59:35 +00:00
|
|
|
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 ...
|
|
|
|
{
|
2017-05-29 19:33:30 +00:00
|
|
|
a_Player->OpenWindow(*Window);
|
2014-07-30 19:59:35 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-01 22:12:44 +00:00
|
|
|
return true;
|
2014-04-11 22:01:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|