From 9749c3aac9dbfbc46a919193c97bb9c9e5339e03 Mon Sep 17 00:00:00 2001 From: Lukas Pioch Date: Thu, 24 Sep 2015 10:48:33 +0200 Subject: Implemented brewing --- src/BlockEntities/BlockEntity.cpp | 2 + src/BlockEntities/BrewingstandEntity.cpp | 309 +++++++++++++++++++++++++++++++ src/BlockEntities/BrewingstandEntity.h | 136 ++++++++++++++ src/BlockEntities/CMakeLists.txt | 2 + 4 files changed, 449 insertions(+) create mode 100644 src/BlockEntities/BrewingstandEntity.cpp create mode 100644 src/BlockEntities/BrewingstandEntity.h (limited to 'src/BlockEntities') diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index c59198e79..0b69830f6 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "BeaconEntity.h" #include "BlockEntity.h" +#include "BrewingstandEntity.h" #include "ChestEntity.h" #include "CommandBlockEntity.h" #include "DispenserEntity.h" @@ -36,6 +37,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); + case E_BLOCK_BREWING_STAND: return new cBrewingstandEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_MOB_SPAWNER: return new cMobSpawnerEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); diff --git a/src/BlockEntities/BrewingstandEntity.cpp b/src/BlockEntities/BrewingstandEntity.cpp new file mode 100644 index 000000000..e34297393 --- /dev/null +++ b/src/BlockEntities/BrewingstandEntity.cpp @@ -0,0 +1,309 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "BrewingstandEntity.h" +#include "../Bindings/PluginManager.h" +#include "../UI/BrewingstandWindow.h" +#include "../Entities/Player.h" +#include "../Root.h" +#include "../Chunk.h" + + + + + + + + + + + + +cBrewingstandEntity::cBrewingstandEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World) : + super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World), + m_BlockMeta(a_BlockMeta), + m_IsDestroyed(false), + m_IsBrewing(false), + m_TimeBrewed(0) +{ + m_Contents.AddListener(*this); + for (int i = 0; i < 3; i++) + { + m_Results[i] = *(new cItem()); + } +} + + + + + +cBrewingstandEntity::~cBrewingstandEntity() +{ + // Tell window its owner is destroyed + cWindow * Window = GetWindow(); + if (Window != nullptr) + { + Window->OwnerDestroyed(); + } +} + + + + + +void cBrewingstandEntity::UsedBy(cPlayer * a_Player) +{ + cWindow * Window = GetWindow(); + if (Window == nullptr) + { + OpenWindow(new cBrewingstandWindow(m_PosX, m_PosY, m_PosZ, this)); + Window = GetWindow(); + } + + if (Window != nullptr) + { + if (a_Player->GetWindow() != Window) + { + a_Player->OpenWindow(Window); + } + } + + if (m_IsBrewing) + { + BroadcastProgress(0, m_NeedBrewingTime - m_TimeBrewed); + } + else + { + BroadcastProgress(0, 0); + } +} + + + + + +bool cBrewingstandEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) +{ + UNUSED(a_Dt); + + if (!m_IsBrewing) + { + return false; + } + + const cBrewingRecipes::cRecipe * Recipe = nullptr; + // The necessary brewing time, has been reached + if (m_TimeBrewed >= m_NeedBrewingTime) + { + BroadcastProgress(0, 0); + m_IsBrewing = false; + m_TimeBrewed = 0; + + // Return if the hook has been canceled + if (cPluginManager::Get()->CallHookBrewingCompleting(*m_World, *this)) + { + return false; + } + + // Decrease item count, full stacks are allowed in the ingredient slot + cItem Ingredient = m_Contents.GetSlot(bsIngredient); + Ingredient.m_ItemCount -= 1; + m_Contents.SetSlot(bsIngredient, Ingredient); + + // Loop over all bottle slots and update available bottles + for (int i = 0; i < 3; i++) + { + if (m_Contents.GetSlot(i).IsEmpty() || (m_CurrentBrewingRecipes[i] == nullptr)) + { + continue; + } + + Recipe = m_CurrentBrewingRecipes[i]; + m_Contents.SetSlot(i, Recipe->Output->CopyOne()); + } + + // Brewing process completed + cPluginManager::Get()->CallHookBrewingCompleted(*m_World, *this); + + return true; + } + + m_TimeBrewed++; + UpdateProgressBars(false); + return false; +} + + + + + + +void cBrewingstandEntity::SendTo(cClientHandle & a_Client) +{ + // Nothing needs to be sent + UNUSED(a_Client); +} + + + + + +void cBrewingstandEntity::BroadcastProgress(short a_ProgressbarID, short a_Value) +{ + cWindow * Window = GetWindow(); + if (Window != nullptr) + { + Window->SetProperty(a_ProgressbarID, a_Value); + } +} + + + + + + +void cBrewingstandEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) +{ + super::OnSlotChanged(a_ItemGrid, a_SlotNum); + + if (m_IsDestroyed) + { + return; + } + + ASSERT(a_ItemGrid == &m_Contents); + + // Check if still a item is in the ingredient slot + if (GetSlot(bsIngredient).IsEmpty()) + { + if (m_IsBrewing) + { + // Cancel brewing + BroadcastProgress(0, 0); + m_IsBrewing = false; + m_TimeBrewed = 0; + } + return; + } + + // Recheck the bottles + cBrewingRecipes * BR = cRoot::Get()->GetBrewingRecipes(); + const cBrewingRecipes::cRecipe * Recipe = nullptr; + bool Stop = true; + for (int i = 0; i < 3; i++) + { + if (GetSlot(i).IsEmpty()) + { + m_CurrentBrewingRecipes[i] = nullptr; + m_Results[i].Clear(); + continue; + } + + if (m_CurrentBrewingRecipes[i] != nullptr) + { + Recipe = m_CurrentBrewingRecipes[i]; + if (Recipe->Ingredient->IsEqual(GetSlot(bsIngredient)) && Recipe->Input->IsEqual(GetSlot(i))) + { + Stop = false; + continue; + } + } + + Recipe = BR->GetRecipeFrom(m_Contents.GetSlot(i), m_Contents.GetSlot(bsIngredient)); + if (Recipe != nullptr) + { + // Found a brewing recipe for the items + m_CurrentBrewingRecipes[i] = Recipe; + m_Results[i] = Recipe->Output->CopyOne(); + Stop = false; + } + } + + if (Stop) + { + if (m_IsBrewing) + { + // Cancel brewing + BroadcastProgress(0, 0); + m_IsBrewing = false; + m_TimeBrewed = 0; + } + return; + } + + // Start brewing process, if not running + if (!m_IsBrewing) + { + m_IsBrewing = true; + } +} + + + + + +void cBrewingstandEntity::UpdateProgressBars(bool a_ForceUpdate) +{ + /** Sending an update every 3th tick, using a higher value lets look the progressbar ugly */ + if (!a_ForceUpdate && (m_World->GetWorldAge() % 3 != 0)) + { + return; + } + + BroadcastProgress(0, m_NeedBrewingTime - m_TimeBrewed); +} + + + + + +void cBrewingstandEntity::setTimeBrewed(short a_TimeBrewed) +{ + m_TimeBrewed = a_TimeBrewed; +} + + + + + +void cBrewingstandEntity::ContinueBrewing(void) +{ + // Continue brewing if number is greater than 0 + if (m_TimeBrewed > 0) + { + m_IsBrewing = true; + } +} + + + + + +void cBrewingstandEntity::GetRecipes(void) +{ + if (GetSlot(3).IsEmpty()) + { + return; + } + + cBrewingRecipes * BR = cRoot::Get()->GetBrewingRecipes(); + const cBrewingRecipes::cRecipe * Recipe = nullptr; + for (int i = 0; i < 3; i++) + { + if (GetSlot(i).IsEmpty()) + { + continue; + } + Recipe = BR->GetRecipeFrom(GetSlot(i), GetSlot(bsIngredient)); + if (Recipe != nullptr) + { + m_CurrentBrewingRecipes[i] = Recipe; + m_Results[i] = Recipe->Output->CopyOne(); + } + } +} + + + + + diff --git a/src/BlockEntities/BrewingstandEntity.h b/src/BlockEntities/BrewingstandEntity.h new file mode 100644 index 000000000..a895c4bde --- /dev/null +++ b/src/BlockEntities/BrewingstandEntity.h @@ -0,0 +1,136 @@ + +#pragma once + +#include "BlockEntityWithItems.h" +#include "../BrewingRecipes.h" +#include "../Root.h" + + + + +class cClientHandle; + + + + + +// tolua_begin +class cBrewingstandEntity : + public cBlockEntityWithItems +{ + typedef cBlockEntityWithItems super; + +public: + enum + { + bsLeftBottle = 0, // Left bottle slot number + bsMiddleBottle = 1, // Middle bottle slot number + bsRightBottle = 2, // Right bottle slot number + bsIngredient = 3, // Top ingredient slot number + + ContentsWidth = 4, + ContentsHeight = 1, + }; + + // tolua_end + + BLOCKENTITY_PROTODEF(cBrewingstandEntity) + + /** Constructor used for normal operation */ + cBrewingstandEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World); + + virtual ~cBrewingstandEntity(); + + // cBlockEntity overrides: + virtual void SendTo(cClientHandle & a_Client) override; + virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; + virtual void UsedBy(cPlayer * a_Player) override; + virtual void Destroy() override + { + m_IsDestroyed = true; + super::Destroy(); + } + + // tolua_begin + + /** Returns the time until the current items finishes brewing, in ticks */ + short GetBrewingTimeLeft(void) const { return m_NeedBrewingTime - m_TimeBrewed; } + + /** Returns the time that the current items has been brewing, in ticks */ + short GetTimeBrewed(void) { return m_TimeBrewed; } + + /** Returns the item in the left bottle slot */ + const cItem & GetLeftBottleSlot(void) const { return GetSlot(bsLeftBottle); } + + /** Returns the item in the middle bottle slot */ + const cItem & GetMiddleBottleSlot(void) const { return GetSlot(bsMiddleBottle); } + + /** Returns the item in the right bottle slot */ + const cItem & GetRightBottleSlot(void) const { return GetSlot(bsRightBottle); } + + /** Returns the item in the ingredient slot */ + const cItem & GetIndgredientSlot(void) const { return GetSlot(bsIngredient); } + + /** Get the expected result item for the given slot number */ + const cItem & GetResultItem(int a_SlotNumber) { return m_Results[a_SlotNumber]; } + + /** Sets the item in the left bottle slot */ + void SetLeftBottleSlot(const cItem & a_Item) { SetSlot(bsLeftBottle, a_Item); } + + /** Sets the item in the middle bottle slot */ + void SetMiddleBottleSlot(const cItem & a_Item) { SetSlot(bsMiddleBottle, a_Item); } + + /** Sets the item in the right bottle slot */ + void SetRightBottleSlot(const cItem & a_Item) { SetSlot(bsRightBottle, a_Item); } + + /** Sets the item in the ingredient slot */ + void SetIngredientSlot(const cItem & a_Item) { SetSlot(bsIngredient, a_Item); } + + // tolua_end + + /** Sets the current brewing time. Will be called if the brewing stand gets loaded from the world. */ + void setTimeBrewed(short a_TimeBrewed); + + /** Starts the brewing proccess. Will be called if the brewing stand gets loaded from the world. */ + void ContinueBrewing(void); + + /** Gets the recipes. Will be called if the brewing stand gets loaded from the world. */ + void GetRecipes(void); +protected: + + /** Block meta of the block currently represented by this entity */ + NIBBLETYPE m_BlockMeta; + + /** Set to true when the brewing stand entity has been destroyed to prevent the block being set again */ + bool m_IsDestroyed; + + /** Set to true if the brewing stand is brewing an item */ + bool m_IsBrewing; + + /** Brewing time is 400 ticks */ + const short m_NeedBrewingTime = 400; + + /** Store the current brewing recipes */ + const cBrewingRecipes::cRecipe * m_CurrentBrewingRecipes[3] = {}; + + /** Result items for the bottle inputs */ + cItem m_Results[3] = {}; + + /** Amount of ticks that the current item has been brewed */ + short m_TimeBrewed; + + /** Sends the specified progressbar value to all clients of the window */ + void BroadcastProgress(short a_ProgressbarID, short a_Value); + + // /** Broadcasts progressbar updates, if needed */ + void UpdateProgressBars(bool a_ForceUpdate = false); + + // cItemGrid::cListener overrides: + virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; + +} ; // tolua_export + + + + + diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt index 0d1776eb5..931484be0 100644 --- a/src/BlockEntities/CMakeLists.txt +++ b/src/BlockEntities/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") SET (SRCS BeaconEntity.cpp BlockEntity.cpp + BrewingstandEntity.cpp ChestEntity.cpp CommandBlockEntity.cpp DispenserEntity.cpp @@ -27,6 +28,7 @@ SET (HDRS BeaconEntity.h BlockEntity.h BlockEntityWithItems.h + BrewingstandEntity.h ChestEntity.h CommandBlockEntity.h DispenserEntity.h -- cgit v1.2.3