[BlockFurnace] Now able to smelt iron ore into ingots, using coal as fuel.

This commit is contained in:
Quentin Bazin 2018-06-29 08:56:59 +02:00
parent da0877f515
commit a258fde36a
15 changed files with 124 additions and 36 deletions

View File

@ -20,5 +20,7 @@ typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;
typedef unsigned long long u64;
typedef signed long long s64;
#endif // INTTYPES_HPP_

View File

@ -24,13 +24,13 @@
class Registry {
public:
template<typename T, typename... Args>
auto registerBlock(Args &&...args) -> typename std::enable_if<std::is_base_of<Block, T>::value>::type {
m_blocks.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
auto registerBlock(Args &&...args) -> typename std::enable_if<std::is_base_of<Block, T>::value, Block&>::type {
return *m_blocks.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)).get();
}
template<typename T, typename... Args>
auto registerItem(Args &&...args) -> typename std::enable_if<std::is_base_of<Item, T>::value>::type {
m_items.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
auto registerItem(Args &&...args) -> typename std::enable_if<std::is_base_of<Item, T>::value, Item&>::type {
return *m_items.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)).get();
}
void registerBlocks();

View File

@ -14,11 +14,12 @@
#ifndef FURNACEWIDGET_HPP_
#define FURNACEWIDGET_HPP_
#include "BlockData.hpp"
#include "InventoryWidget.hpp"
class FurnaceWidget : public Widget {
public:
FurnaceWidget(Inventory &playerInventory, Inventory &hotbarInventory, Widget *parent = nullptr);
FurnaceWidget(Inventory &playerInventory, Inventory &hotbarInventory, BlockData &blockData, Widget *parent = nullptr);
void onEvent(const SDL_Event &event) override;
@ -35,6 +36,12 @@ class FurnaceWidget : public Widget {
Inventory &m_hotbarInventory;
InventoryWidget m_hotbarInventoryWidget{this};
InventoryWidget m_inputInventoryWidget{this};
InventoryWidget m_outputInventoryWidget{this};
InventoryWidget m_fuelInventoryWidget{this};
BlockData &m_blockData;
MouseItemWidget m_mouseItemWidget{this};
};

View File

@ -22,7 +22,7 @@ class InventoryWidget : public Widget {
public:
InventoryWidget(Widget *parent = nullptr) : Widget(parent) {}
void init(Inventory &inventory);
void init(Inventory &inventory, unsigned int offset = 0, unsigned int size = 0);
void onMouseEvent(const SDL_Event &event, MouseItemWidget &mouseItemWidget, bool isReadOnly = false);

View File

@ -31,6 +31,7 @@ namespace BlockType {
Glowstone = 12,
Workbench = 13,
Furnace = 14,
IronOre = 15,
};
}

View File

@ -29,9 +29,17 @@ class Item {
u32 textureID() const { return m_textureID; }
bool isBlock() const { return m_isBlock; }
bool isFuel() const { return m_isFuel; }
void setIsFuel(bool isFuel) { m_isFuel = isFuel; }
u16 burnTime() const { return m_burnTime; }
void setBurnTime(u16 burnTime) { m_burnTime = burnTime; }
protected:
bool m_isBlock = false;
bool m_isFuel = false;
u16 m_burnTime = 0;
private:
std::string m_name;

View File

@ -31,13 +31,16 @@ namespace ItemType {
Glowstone = 12,
Workbench = 13,
Furnace = 14,
IronOre = 15,
Stick = 15,
StoneAxe = 16,
StoneHoe = 17,
StonePickaxe = 18,
StoneShovel = 19,
StoneSword = 20,
Stick = 16,
StoneAxe = 17,
StoneHoe = 18,
StonePickaxe = 19,
StoneShovel = 20,
StoneSword = 21,
Coal = 22,
IronIngot = 23
};
}

View File

@ -20,6 +20,8 @@ struct BlockData {
BlockData(int width, int height) : inventory(width, height) {}
Inventory inventory;
u64 data = 0;
};
#endif // BLOCKDATA_HPP_

View File

@ -20,7 +20,7 @@ class BlockFurnace : public Block {
public:
BlockFurnace();
bool onBlockActivated(const glm::ivec3 &position, Player &player, World &world) const override;
bool onBlockActivated(const glm::ivec3 &blockPosition, Player &player, World &world) const override;
void onTick(const glm::ivec3 &blockPosition, Player &player, Chunk &chunk, World &world) const override;
};

View File

@ -36,6 +36,7 @@ void Registry::registerBlocks() {
registerBlock<Block>(BlockType::Glowstone, 218);
registerBlock<BlockWorkbench>();
registerBlock<BlockFurnace>();
registerBlock<Block>(BlockType::IronOre, 254);
}
void Registry::registerItems() {
@ -54,6 +55,7 @@ void Registry::registerItems() {
registerItem<ItemBlock>(ItemType::Glowstone, BlockType::Glowstone, "Glowstone");
registerItem<ItemBlock>(ItemType::Workbench, BlockType::Workbench, "Workbench");
registerItem<ItemBlock>(ItemType::Furnace, BlockType::Furnace, "Furnace");
registerItem<ItemBlock>(ItemType::IronOre, BlockType::IronOre, "Iron Ore");
registerItem<Item>(ItemType::Stick, 324, "Stick");
registerItem<Item>(ItemType::StoneAxe, 325, "Stone Axe");
@ -62,6 +64,12 @@ void Registry::registerItems() {
registerItem<Item>(ItemType::StoneShovel, 328, "Stone Shovel");
registerItem<Item>(ItemType::StoneSword, 329, "Stone Sword");
Item &itemCoal = registerItem<Item>(ItemType::Coal, 111, "Coal");
itemCoal.setIsFuel(true);
itemCoal.setBurnTime(1600);
registerItem<Item>(ItemType::IronIngot, 232, "Iron Ingot");
// FIXME: Move this to Application or load from XML file
registerRecipes();
}

View File

@ -13,8 +13,8 @@
*/
#include "FurnaceWidget.hpp"
FurnaceWidget::FurnaceWidget(Inventory &playerInventory, Inventory &hotbarInventory, Widget *parent)
: Widget(176, 166, parent), m_playerInventory(playerInventory), m_hotbarInventory(hotbarInventory)
FurnaceWidget::FurnaceWidget(Inventory &playerInventory, Inventory &hotbarInventory, BlockData &blockData, Widget *parent)
: Widget(176, 166, parent), m_playerInventory(playerInventory), m_hotbarInventory(hotbarInventory), m_blockData(blockData)
{
m_background.load("texture-furnace");
m_background.setClipRect(0, 0, 176, 166);
@ -24,19 +24,34 @@ FurnaceWidget::FurnaceWidget(Inventory &playerInventory, Inventory &hotbarInvent
m_hotbarInventoryWidget.init(m_hotbarInventory);
m_hotbarInventoryWidget.setPosition(7, 141, 0);
m_inputInventoryWidget.setPosition(55, 16, 0);
m_outputInventoryWidget.setPosition(115, 34, 0);
m_fuelInventoryWidget.setPosition(55, 52, 0);
}
void FurnaceWidget::onEvent(const SDL_Event &event) {
m_playerInventoryWidget.onMouseEvent(event, m_mouseItemWidget);
m_hotbarInventoryWidget.onMouseEvent(event, m_mouseItemWidget);
m_inputInventoryWidget.onMouseEvent(event, m_mouseItemWidget);
m_outputInventoryWidget.onMouseEvent(event, m_mouseItemWidget);
m_fuelInventoryWidget.onMouseEvent(event, m_mouseItemWidget);
m_mouseItemWidget.onEvent(event);
}
void FurnaceWidget::update() {
m_inputInventoryWidget.init(m_blockData.inventory, 0, 1);
m_outputInventoryWidget.init(m_blockData.inventory, 1, 1);
m_fuelInventoryWidget.init(m_blockData.inventory, 2, 1);
const ItemWidget *currentItemWidget = nullptr;
if ((currentItemWidget = m_playerInventoryWidget.currentItemWidget())
|| (currentItemWidget = m_hotbarInventoryWidget.currentItemWidget()))
|| (currentItemWidget = m_hotbarInventoryWidget.currentItemWidget())
|| (currentItemWidget = m_inputInventoryWidget.currentItemWidget())
|| (currentItemWidget = m_outputInventoryWidget.currentItemWidget())
|| (currentItemWidget = m_fuelInventoryWidget.currentItemWidget()))
m_mouseItemWidget.update(currentItemWidget);
else
m_mouseItemWidget.update(nullptr);
@ -50,6 +65,10 @@ void FurnaceWidget::draw(RenderTarget &target, RenderStates states) const {
target.draw(m_playerInventoryWidget, states);
target.draw(m_hotbarInventoryWidget, states);
target.draw(m_inputInventoryWidget, states);
target.draw(m_outputInventoryWidget, states);
target.draw(m_fuelInventoryWidget, states);
target.draw(m_mouseItemWidget, states);
}

View File

@ -13,15 +13,15 @@
*/
#include "InventoryWidget.hpp"
void InventoryWidget::init(Inventory &inventory) {
void InventoryWidget::init(Inventory &inventory, unsigned int offset, unsigned int size) {
m_itemWidgets.clear();
for (u16 y = 0 ; y < inventory.height() ; ++y) {
for (u16 x = 0 ; x < inventory.width() ; ++x) {
ItemWidget &widget = m_itemWidgets.emplace_back(inventory, x, y, this);
widget.update();
widget.setPosition(x * 18, y * 18, 0);
}
// for (u16 y = 0 ; y < inventory.height() ; ++y) {
// for (u16 x = 0 ; x < inventory.width() ; ++x) {
for (u16 i = 0 ; i < (size > 0 ? size : inventory.width() * inventory.height()) ; ++i) {
ItemWidget &widget = m_itemWidgets.emplace_back(inventory, (i + offset) % inventory.width(), (i + offset) / inventory.width(), this);
widget.update();
widget.setPosition((i % inventory.width()) * 18, (i / inventory.width()) * 18, 0);
}
m_width = inventory.width() * 18;

View File

@ -44,6 +44,8 @@ GameState::GameState() {
m_player.inventory().addStack(ItemType::StonePickaxe, 1);
m_player.inventory().addStack(ItemType::StoneShovel, 1);
m_player.inventory().addStack(ItemType::StoneSword, 1);
m_player.inventory().addStack(ItemType::IronOre, 64);
m_player.inventory().addStack(ItemType::Coal, 64);
m_projectionMatrix = glm::perspective(45.0f, (float)SCREEN_WIDTH / SCREEN_HEIGHT, DIST_NEAR, DIST_FAR);

View File

@ -13,19 +13,57 @@
*/
#include "ApplicationStateStack.hpp"
#include "BlockFurnace.hpp"
#include "Exception.hpp"
#include "FurnaceWidget.hpp"
#include "InventoryState.hpp"
#include "Player.hpp"
#include "World.hpp"
BlockFurnace::BlockFurnace() : Block(BlockType::Furnace, 164) {
m_canUpdate = true;
}
bool BlockFurnace::onBlockActivated(const glm::ivec3 &, Player &player, World &) const {
bool BlockFurnace::onBlockActivated(const glm::ivec3 &blockPosition, Player &player, World &world) const {
BlockData *data = world.getBlockData(blockPosition.x, blockPosition.y, blockPosition.z);
if (!data)
throw EXCEPTION("BlockFurnace at (", blockPosition.x, blockPosition.y, blockPosition.z, ") has no inventory");
auto &inventoryState = ApplicationStateStack::getInstance().push<InventoryState>(&ApplicationStateStack::getInstance().top());
inventoryState.setupWidget<FurnaceWidget>(player.inventory(), player.hotbarInventory());
inventoryState.setupWidget<FurnaceWidget>(player.inventory(), player.hotbarInventory(), *data);
return true;
}
void BlockFurnace::onTick(const glm::ivec3 &blockPosition, Player &player, Chunk &chunk, World &world) const {
void BlockFurnace::onTick(const glm::ivec3 &blockPosition, Player &, Chunk &, World &world) const {
BlockData *data = world.getBlockData(blockPosition.x, blockPosition.y, blockPosition.z);
if (!data)
throw EXCEPTION("BlockFurnace at (", blockPosition.x, blockPosition.y, blockPosition.z, ") has no inventory");
const ItemStack &inputStack = data->inventory.getStack(0, 0);
const ItemStack &outputStack = data->inventory.getStack(1, 0);
const ItemStack &fuelStack = data->inventory.getStack(2, 0);
u16 ticksRemaining = data->data & 0xffff;
u16 itemProgress = (data->data >> 16) & 0xffff;
DEBUG((int)ticksRemaining, (int)itemProgress, fuelStack.amount());
if (ticksRemaining == 0 && fuelStack.amount() && inputStack.amount() && inputStack.item().id() == ItemType::IronOre) {
data->inventory.setStack(2, 0, fuelStack.item().id(), fuelStack.amount() - 1);
ticksRemaining = fuelStack.item().burnTime();
}
else if (ticksRemaining > 0 && (!outputStack.amount() || !outputStack.item().id() || outputStack.item().id() == ItemType::IronIngot)) { // FIXME
--ticksRemaining;
++itemProgress;
}
if (itemProgress > 200) {
itemProgress = 0;
if (inputStack.item().id() == ItemType::IronOre && inputStack.amount()) {
data->inventory.setStack(0, 0, inputStack.item().id(), inputStack.amount() - 1);
data->inventory.setStack(1, 0, ItemType::IronIngot);
}
}
data->data = ticksRemaining | (itemProgress << 16);
}

View File

@ -24,15 +24,7 @@ Chunk::Chunk(s32 x, s32 y, s32 z, Texture &texture) : m_texture(texture) {
}
void Chunk::update(Player &player, World &world) {
if (!m_isChanged) return;
m_isChanged = false;
m_lightmap.updateLights();
m_verticesCount = m_builder.buildChunk(*this, m_vbo);
if (m_lastTick < GameClock::getTicks() / 50) {
if (!m_tickingBlocks.empty() && m_lastTick < GameClock::getTicks() / 50) {
m_lastTick = GameClock::getTicks() / 50;
for (auto &it : m_tickingBlocks) {
@ -42,6 +34,12 @@ void Chunk::update(Player &player, World &world) {
it.second.onTick(glm::ivec3{x + m_x * width, y + m_y * height, z + m_z * depth}, player, *this, world);
}
}
if (m_isChanged) {
m_isChanged = false;
m_lightmap.updateLights();
m_verticesCount = m_builder.buildChunk(*this, m_vbo);
}
}
u32 Chunk::getBlock(int x, int y, int z) const {
@ -84,7 +82,7 @@ void Chunk::setBlock(int x, int y, int z, u32 type) {
if (type == BlockType::Workbench)
m_blockData.emplace(Vector3i{x, y, z}, BlockData{3, 3});
else if (type == BlockType::Furnace)
m_blockData.emplace(Vector3i{x, y, z}, BlockData{1, 3});
m_blockData.emplace(Vector3i{x, y, z}, BlockData{3, 1});
if (m_data[x][y][z] == BlockType::Workbench || m_data[x][y][z] == BlockType::Furnace) {
auto it = m_blockData.find(Vector3i{x, y, z});