Added beacon.
This commit is contained in:
parent
f095e770b8
commit
89b1bbdc5f
@ -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_PrimaryPotion(cEntityEffect::effNoEffect)
|
||||
, m_SecondaryPotion(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,122 @@ 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::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel)
|
||||
{
|
||||
if (a_Potion == cEntityEffect::effNoEffect)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (a_BeaconLevel)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
// Beacon level 4
|
||||
if (a_Potion == cEntityEffect::effRegeneration)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
// Beacon level 3
|
||||
if (a_Potion == cEntityEffect::effStrength)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// Beacon level 2
|
||||
switch (a_Potion)
|
||||
{
|
||||
case cEntityEffect::effResistance:
|
||||
case cEntityEffect::effJumpBoost:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// Beacon level 1
|
||||
switch (a_Potion)
|
||||
{
|
||||
case cEntityEffect::effSpeed:
|
||||
case cEntityEffect::effHaste:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBeaconEntity::SelectPrimaryPotion(cEntityEffect::eType a_Potion)
|
||||
{
|
||||
LOG("SelectPrimaryPotion!");
|
||||
if (!IsValidPotion(a_Potion, m_BeaconLevel))
|
||||
{
|
||||
LOG("FALLSE!");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_PrimaryPotion = a_Potion;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBeaconEntity::SelectSecondaryPotion(cEntityEffect::eType a_Potion)
|
||||
{
|
||||
if (!IsValidPotion(a_Potion, m_BeaconLevel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_SecondaryPotion = a_Potion;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBeaconEntity::IsBeaconBlocked(void)
|
||||
{
|
||||
bool IsBlocked = false;
|
||||
for (int Y = m_PosY; Y < cChunkDef::Height; ++Y)
|
||||
{
|
||||
BLOCKTYPE Block = m_World->GetBlock(m_PosX, Y, m_PosZ);
|
||||
if (!cBlockInfo::IsTransparent(Block))
|
||||
{
|
||||
IsBlocked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return IsBlocked;
|
||||
}
|
||||
|
||||
|
||||
@ -83,8 +189,102 @@ bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
|
||||
|
||||
|
||||
|
||||
void cBeaconEntity::UpdateBeacon(void)
|
||||
{
|
||||
if (IsBeaconBlocked())
|
||||
{
|
||||
m_IsActive = false;
|
||||
m_BeaconLevel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BeaconLevel = CalculatePyramidLevel();
|
||||
m_IsActive = (m_BeaconLevel > 0);
|
||||
}
|
||||
|
||||
// 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_PrimaryPotion == m_SecondaryPotion))
|
||||
{
|
||||
EffectLevel = 1;
|
||||
}
|
||||
|
||||
cEntityEffect::eType SecondaryPotion = cEntityEffect::effNoEffect;
|
||||
if ((m_BeaconLevel >= 4) && (m_PrimaryPotion != m_SecondaryPotion) && (m_SecondaryPotion > 0))
|
||||
{
|
||||
SecondaryPotion = m_SecondaryPotion;
|
||||
}
|
||||
|
||||
class cPlayerCallback : public cPlayerListCallback
|
||||
{
|
||||
int m_Radius;
|
||||
int m_PosX, m_PosY, m_PosZ;
|
||||
cEntityEffect::eType m_PrimaryPotion, m_SecondaryPotion;
|
||||
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_PrimaryPotion, 180, m_EffectLevel);
|
||||
|
||||
if (m_SecondaryPotion != cEntityEffect::effNoEffect)
|
||||
{
|
||||
a_Player->AddEntityEffect(m_SecondaryPotion, 180, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryPotion, cEntityEffect::eType a_SecondaryPotion, short a_EffectLevel)
|
||||
: m_Radius(a_Radius)
|
||||
, m_PosX(a_PosX)
|
||||
, m_PosY(a_PosY)
|
||||
, m_PosZ(a_PosZ)
|
||||
, m_PrimaryPotion(a_PrimaryPotion)
|
||||
, m_SecondaryPotion(a_SecondaryPotion)
|
||||
, m_EffectLevel(a_EffectLevel)
|
||||
{};
|
||||
|
||||
} PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryPotion, SecondaryPotion, 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 +292,94 @@ bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
|
||||
|
||||
|
||||
void cBeaconEntity::SaveToJson(Json::Value& a_Value)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void cBeaconEntity::SendTo(cClientHandle & a_Client)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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 PrimaryPotion = a_Value.get("PrimaryPotion", 0).asInt();
|
||||
int SecondaryPotion = a_Value.get("SecondaryPotion", 0).asInt();
|
||||
|
||||
if ((PrimaryPotion >= 0) && (PrimaryPotion <= (int)cEntityEffect::effSaturation))
|
||||
{
|
||||
m_PrimaryPotion = (cEntityEffect::eType)PrimaryPotion;
|
||||
}
|
||||
|
||||
if ((SecondaryPotion >= 0) && (SecondaryPotion <= (int)cEntityEffect::effSaturation))
|
||||
{
|
||||
m_SecondaryPotion = (cEntityEffect::eType)SecondaryPotion;
|
||||
}
|
||||
|
||||
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["PrimaryPotion"] = (int)m_PrimaryPotion;
|
||||
a_Value["SecondaryPotion"] = (int)m_SecondaryPotion;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBeaconEntity::SendTo(cClientHandle & a_Client)
|
||||
{
|
||||
a_Client.SendUpdateBlockEntity(*this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlockEntity.h"
|
||||
#include "BlockEntityWithItems.h"
|
||||
|
||||
|
||||
|
||||
@ -17,26 +17,60 @@ namespace Json
|
||||
|
||||
|
||||
class cBeaconEntity :
|
||||
public cBlockEntity
|
||||
public cBlockEntityWithItems
|
||||
{
|
||||
typedef cBlockEntity super;
|
||||
typedef cBlockEntityWithItems super;
|
||||
|
||||
public:
|
||||
|
||||
/** The initial constructor */
|
||||
cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
|
||||
/** Returns the amount of layers the pyramid below the beacon has. */
|
||||
int GetPyramidLevel(void);
|
||||
|
||||
/** Is the beacon active? */
|
||||
bool IsActive(void) const { return m_IsActive; }
|
||||
|
||||
/** Returns the beacon level. (0 - 4) */
|
||||
char GetBeaconLevel(void) const { return m_BeaconLevel; }
|
||||
|
||||
char GetPrimaryPotion(void) const { return m_PrimaryPotion; }
|
||||
char GetSecondaryPotion(void) const { return m_SecondaryPotion; }
|
||||
|
||||
/** Select the primary potion. Returns false when the potion is invalid.*/
|
||||
bool SelectPrimaryPotion(cEntityEffect::eType a_Potion);
|
||||
|
||||
/** Select the secondary potion. Returns false when the potion is invalid. */
|
||||
bool SelectSecondaryPotion(cEntityEffect::eType a_Potion);
|
||||
|
||||
/** Calculate the amount of layers the pyramid below the beacon has. */
|
||||
char CalculatePyramidLevel(void);
|
||||
|
||||
/** Is the beacon blocked by non-transparent blocks that are higher than the beacon? */
|
||||
bool IsBeaconBlocked(void);
|
||||
|
||||
/** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */
|
||||
static bool IsMineralBlock(BLOCKTYPE a_BlockType);
|
||||
|
||||
/** Returns true if the potion can be used. */
|
||||
static bool IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel);
|
||||
|
||||
/** Update the beacon. */
|
||||
void UpdateBeacon(void);
|
||||
|
||||
/** Give the near-players the effects. */
|
||||
void GiveEffects(void);
|
||||
|
||||
bool LoadFromJson(const Json::Value & a_Value);
|
||||
|
||||
// cBlockEntity overrides:
|
||||
virtual void SaveToJson(Json::Value& a_Value) override;
|
||||
virtual void SendTo(cClientHandle & a_Client) override;
|
||||
virtual void UsedBy(cPlayer * a_Player) override;
|
||||
virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) override;
|
||||
virtual void SaveToJson(Json::Value& a_Value) override;
|
||||
virtual void SendTo(cClientHandle & a_Client) override;
|
||||
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void UsedBy(cPlayer * a_Player) override;
|
||||
|
||||
protected:
|
||||
bool m_IsActive;
|
||||
char m_BeaconLevel;
|
||||
|
||||
cEntityEffect::eType m_PrimaryPotion, m_SecondaryPotion;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
// FlowerPotEntity.cpp
|
||||
|
||||
// Implements the cFlowerPotEntity class representing a single sign in the world
|
||||
// Implements the cFlowerPotEntity class representing a single flower pot in the world
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
#include "json/json.h"
|
||||
|
@ -181,6 +181,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
|
||||
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
|
||||
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
|
||||
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
|
||||
case E_BLOCK_BEACON: return new cBlockEntityHandler (a_BlockType);
|
||||
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
|
||||
case E_BLOCK_BIG_FLOWER: return new cBlockBigFlowerHandler (a_BlockType);
|
||||
case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
|
||||
|
@ -94,6 +94,7 @@ private:
|
||||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_ANVIL:
|
||||
case E_BLOCK_BEACON:
|
||||
case E_BLOCK_BEDROCK:
|
||||
case E_BLOCK_BREWING_STAND:
|
||||
case E_BLOCK_CHEST:
|
||||
|
@ -1839,6 +1839,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
}
|
||||
|
||||
case E_BLOCK_OBSIDIAN:
|
||||
case E_BLOCK_BEACON:
|
||||
case E_BLOCK_BEDROCK:
|
||||
case E_BLOCK_WATER:
|
||||
case E_BLOCK_LAVA:
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "Items/ItemSword.h"
|
||||
|
||||
#include "polarssl/md5.h"
|
||||
#include "BlockEntities/BeaconEntity.h"
|
||||
|
||||
|
||||
|
||||
@ -659,6 +660,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
|
||||
// Client <-> Server branding exchange
|
||||
SendPluginMessage("MC|Brand", "MCServer");
|
||||
}
|
||||
else if (a_Channel == "MC|Beacon")
|
||||
{
|
||||
HandleBeaconSelection(a_Message.c_str(), a_Message.size());
|
||||
}
|
||||
else if (a_Channel == "MC|ItemName")
|
||||
{
|
||||
HandleAnvilItemName(a_Message.c_str(), a_Message.size());
|
||||
@ -746,6 +751,55 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length)
|
||||
{
|
||||
if (a_Length < 14)
|
||||
{
|
||||
SendChat("Failure setting beacon selection; bad request", mtFailure);
|
||||
LOGD("Malformed MC|Beacon packet.");
|
||||
return;
|
||||
}
|
||||
|
||||
cWindow * Window = m_Player->GetWindow();
|
||||
if ((Window == NULL) || (Window->GetWindowType() != cWindow::wtBeacon))
|
||||
{
|
||||
return;
|
||||
}
|
||||
cBeaconWindow * BeaconWindow = (cBeaconWindow *) Window;
|
||||
|
||||
if (Window->GetSlot(*m_Player, 0)->IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cByteBuffer Buffer(a_Length);
|
||||
Buffer.Write(a_Data, a_Length);
|
||||
|
||||
int PrimaryPotionID, SecondaryPotionID;
|
||||
Buffer.ReadBEInt(PrimaryPotionID);
|
||||
Buffer.ReadBEInt(SecondaryPotionID);
|
||||
|
||||
cEntityEffect::eType PrimaryPotion = cEntityEffect::effNoEffect;
|
||||
if ((PrimaryPotionID >= 0) && (PrimaryPotionID <= (int)cEntityEffect::effSaturation))
|
||||
{
|
||||
PrimaryPotion = (cEntityEffect::eType)PrimaryPotionID;
|
||||
}
|
||||
|
||||
cEntityEffect::eType SecondaryPotion = cEntityEffect::effNoEffect;
|
||||
if ((SecondaryPotionID >= 0) && (SecondaryPotionID <= (int)cEntityEffect::effSaturation))
|
||||
{
|
||||
SecondaryPotion = (cEntityEffect::eType)SecondaryPotionID;
|
||||
}
|
||||
|
||||
Window->SetSlot(*m_Player, 0, cItem());
|
||||
BeaconWindow->GetBeaconEntity()->SelectPrimaryPotion(PrimaryPotion);
|
||||
BeaconWindow->GetBeaconEntity()->SelectSecondaryPotion(SecondaryPotion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length)
|
||||
{
|
||||
if (a_Length < 14)
|
||||
|
@ -399,7 +399,10 @@ private:
|
||||
|
||||
/** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */
|
||||
void UnregisterPluginChannels(const AStringVector & a_ChannelList);
|
||||
|
||||
|
||||
/** Handles the "MC|Beacon" plugin message */
|
||||
void HandleBeaconSelection(const char * a_Data, size_t a_Length);
|
||||
|
||||
/** Handles the "MC|AdvCdm" plugin message */
|
||||
void HandleCommandBlockMessage(const char * a_Data, size_t a_Length);
|
||||
|
||||
|
@ -37,6 +37,7 @@ Implements the 1.7.x protocol classes:
|
||||
#include "../Mobs/IncludeAllMonsters.h"
|
||||
#include "../UI/Window.h"
|
||||
|
||||
#include "../BlockEntities/BeaconEntity.h"
|
||||
#include "../BlockEntities/CommandBlockEntity.h"
|
||||
#include "../BlockEntities/MobHeadEntity.h"
|
||||
#include "../BlockEntities/FlowerPotEntity.h"
|
||||
@ -1328,6 +1329,7 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
|
||||
{
|
||||
case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing
|
||||
case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text
|
||||
case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity
|
||||
case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity
|
||||
case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
|
||||
default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
|
||||
@ -2581,6 +2583,19 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
|
||||
|
||||
switch (a_BlockEntity.GetBlockType())
|
||||
{
|
||||
case E_BLOCK_BEACON:
|
||||
{
|
||||
cBeaconEntity & BeaconEntity = (cBeaconEntity &)a_BlockEntity;
|
||||
|
||||
Writer.AddInt("x", BeaconEntity.GetPosX());
|
||||
Writer.AddInt("y", BeaconEntity.GetPosY());
|
||||
Writer.AddInt("z", BeaconEntity.GetPosZ());
|
||||
Writer.AddInt("Primary", BeaconEntity.GetPrimaryPotion());
|
||||
Writer.AddInt("Secondary", BeaconEntity.GetSecondaryPotion());
|
||||
Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel());
|
||||
Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_COMMAND_BLOCK:
|
||||
{
|
||||
cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "Globals.h"
|
||||
#include "SlotArea.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../BlockEntities/BeaconEntity.h"
|
||||
#include "../BlockEntities/ChestEntity.h"
|
||||
#include "../BlockEntities/DropSpenserEntity.h"
|
||||
#include "../BlockEntities/EnderChestEntity.h"
|
||||
@ -1190,6 +1191,200 @@ void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player)
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cSlotAreaBeacon:
|
||||
|
||||
cSlotAreaBeacon::cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow) :
|
||||
cSlotArea(1, a_ParentWindow),
|
||||
m_Beacon(a_Beacon)
|
||||
{
|
||||
m_Beacon->GetContents().AddListener(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cSlotAreaBeacon::~cSlotAreaBeacon()
|
||||
{
|
||||
m_Beacon->GetContents().RemoveListener(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSlotAreaBeacon::IsPlaceableItem(short a_ItemType)
|
||||
{
|
||||
switch (a_ItemType)
|
||||
{
|
||||
case E_ITEM_EMERALD:
|
||||
case E_ITEM_DIAMOND:
|
||||
case E_ITEM_GOLD:
|
||||
case E_ITEM_IRON:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
|
||||
{
|
||||
ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
|
||||
|
||||
bool bAsync = false;
|
||||
if (GetSlot(a_SlotNum, a_Player) == NULL)
|
||||
{
|
||||
LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a_ClickAction)
|
||||
{
|
||||
case caShiftLeftClick:
|
||||
case caShiftRightClick:
|
||||
{
|
||||
ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
|
||||
return;
|
||||
}
|
||||
case caMiddleClick:
|
||||
{
|
||||
MiddleClicked(a_Player, a_SlotNum);
|
||||
return;
|
||||
}
|
||||
case caDropKey:
|
||||
case caCtrlDropKey:
|
||||
{
|
||||
DropClicked(a_Player, a_SlotNum, false);
|
||||
return;
|
||||
}
|
||||
case caNumber1:
|
||||
case caNumber2:
|
||||
case caNumber3:
|
||||
case caNumber4:
|
||||
case caNumber5:
|
||||
case caNumber6:
|
||||
case caNumber7:
|
||||
case caNumber8:
|
||||
case caNumber9:
|
||||
{
|
||||
NumberClicked(a_Player, a_SlotNum, a_ClickAction);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cItem Slot(*GetSlot(a_SlotNum, a_Player));
|
||||
if (!Slot.IsSameType(a_ClickedItem))
|
||||
{
|
||||
LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
|
||||
LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
|
||||
LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
|
||||
bAsync = true;
|
||||
}
|
||||
cItem & DraggingItem = a_Player.GetDraggingItem();
|
||||
|
||||
if (DraggingItem.IsEmpty())
|
||||
{
|
||||
DraggingItem = Slot;
|
||||
Slot.Empty();
|
||||
}
|
||||
else if (Slot.IsEmpty())
|
||||
{
|
||||
if (!IsPlaceableItem(DraggingItem.m_ItemType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Slot = DraggingItem.CopyOne();
|
||||
DraggingItem.m_ItemCount -= 1;
|
||||
if (DraggingItem.m_ItemCount <= 0)
|
||||
{
|
||||
DraggingItem.Empty();
|
||||
}
|
||||
}
|
||||
else if (DraggingItem.m_ItemCount == 1)
|
||||
{
|
||||
if (!IsPlaceableItem(DraggingItem.m_ItemCount))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch contents
|
||||
cItem tmp(DraggingItem);
|
||||
DraggingItem = Slot;
|
||||
Slot = tmp;
|
||||
}
|
||||
|
||||
SetSlot(a_SlotNum, a_Player, Slot);
|
||||
if (bAsync)
|
||||
{
|
||||
m_ParentWindow.BroadcastWholeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
|
||||
{
|
||||
const cItem * Slot = GetSlot(0, a_Player);
|
||||
if (!Slot->IsEmpty() || !IsPlaceableItem(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemCount != 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (a_ShouldApply)
|
||||
{
|
||||
SetSlot(0, a_Player, a_ItemStack.CopyOne());
|
||||
}
|
||||
a_ItemStack.Empty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cItem * cSlotAreaBeacon::GetSlot(int a_SlotNum, cPlayer & a_Player) const
|
||||
{
|
||||
UNUSED(a_Player);
|
||||
return &(m_Beacon->GetSlot(a_SlotNum));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSlotAreaBeacon::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
|
||||
{
|
||||
UNUSED(a_Player);
|
||||
m_Beacon->SetSlot(a_SlotNum, a_Item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
|
||||
{
|
||||
UNUSED(a_SlotNum);
|
||||
// Something has changed in the window, broadcast the entire window to all clients
|
||||
ASSERT(a_ItemGrid == &(m_Beacon->GetContents()));
|
||||
|
||||
m_ParentWindow.BroadcastWholeWindow();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cSlotAreaEnchanting:
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
class cWindow;
|
||||
class cPlayer;
|
||||
class cBeaconEntity;
|
||||
class cChestEntity;
|
||||
class cDropSpenserEntity;
|
||||
class cEnderChestEntity;
|
||||
@ -314,6 +315,34 @@ protected:
|
||||
|
||||
|
||||
|
||||
class cSlotAreaBeacon :
|
||||
public cSlotArea,
|
||||
public cItemGrid::cListener
|
||||
{
|
||||
typedef cSlotArea super;
|
||||
|
||||
public:
|
||||
cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow);
|
||||
virtual ~cSlotAreaBeacon();
|
||||
|
||||
bool IsPlaceableItem(short a_ItemType);
|
||||
|
||||
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
|
||||
virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
|
||||
virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override;
|
||||
virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
|
||||
|
||||
protected:
|
||||
cBeaconEntity * m_Beacon;
|
||||
|
||||
// cItemGrid::cListener overrides:
|
||||
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cSlotAreaEnchanting :
|
||||
public cSlotAreaTemporary
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "../Entities/Pickup.h"
|
||||
#include "../Inventory.h"
|
||||
#include "../Items/ItemHandler.h"
|
||||
#include "../BlockEntities/BeaconEntity.h"
|
||||
#include "../BlockEntities/ChestEntity.h"
|
||||
#include "../BlockEntities/DropSpenserEntity.h"
|
||||
#include "../BlockEntities/EnderChestEntity.h"
|
||||
@ -840,6 +841,36 @@ void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cBeaconWindow:
|
||||
|
||||
cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) :
|
||||
cWindow(wtBeacon, "Beacon"),
|
||||
m_Beacon(a_Beacon)
|
||||
{
|
||||
m_ShouldDistributeToHotbarFirst = true;
|
||||
m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this));
|
||||
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
|
||||
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player)
|
||||
{
|
||||
super::OpenedByPlayer(a_Player);
|
||||
|
||||
a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel());
|
||||
a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryPotion());
|
||||
a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryPotion());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cEnchantingWindow:
|
||||
|
||||
|
@ -23,6 +23,7 @@ class cDropSpenserEntity;
|
||||
class cEnderChestEntity;
|
||||
class cFurnaceEntity;
|
||||
class cHopperEntity;
|
||||
class cBeaconEntity;
|
||||
class cSlotArea;
|
||||
class cSlotAreaAnvil;
|
||||
class cWorld;
|
||||
@ -258,6 +259,26 @@ protected:
|
||||
|
||||
|
||||
|
||||
class cBeaconWindow :
|
||||
public cWindow
|
||||
{
|
||||
typedef cWindow super;
|
||||
public:
|
||||
cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon);
|
||||
|
||||
cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; }
|
||||
|
||||
// cWindow Overrides:
|
||||
virtual void OpenedByPlayer(cPlayer & a_Player) override;
|
||||
|
||||
protected:
|
||||
cBeaconEntity * m_Beacon;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEnchantingWindow :
|
||||
public cWindow
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user