diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 52f4ffa0..0c25b6da 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -436,8 +436,8 @@ void ContentLoader::loadItem( root.at("script-name").get(def.scriptName); root.at("model-name").get(def.modelName); root.at("stack-size").get(def.stackSize); + root.at("uses").get(def.uses); - // item light emission [r, g, b] where r,g,b in range [0..15] if (auto found = root.at("emission")) { const auto& emissionarr = *found; def.emission[0] = emissionarr[0].asNumber(); diff --git a/src/graphics/core/Batch2D.hpp b/src/graphics/core/Batch2D.hpp index 6bfdb14d..5610f603 100644 --- a/src/graphics/core/Batch2D.hpp +++ b/src/graphics/core/Batch2D.hpp @@ -48,10 +48,15 @@ public: void sprite(float x, float y, float w, float h, float skew, int atlasRes, int index, glm::vec4 tint); void point(float x, float y, float r, float g, float b, float a); - inline void setColor(glm::vec4 color) { + void setColor(glm::vec4 color) { this->color = color; } - inline glm::vec4 getColor() const { + + void resetColor() { + this->color = glm::vec4(1.0f); + } + + glm::vec4 getColor() const { return color; } diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index 9c180e2e..3735260c 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -8,7 +8,6 @@ #include "items/Inventories.hpp" #include "items/Inventory.hpp" #include "items/ItemDef.hpp" -#include "items/ItemStack.hpp" #include "logic/scripting/scripting.hpp" #include "maths/voxmaths.hpp" #include "objects/Player.hpp" @@ -115,26 +114,73 @@ SlotView::SlotView( setTooltipDelay(0.0f); } +void SlotView::refreshTooltip(const ItemStack& stack, const ItemDef& item) { + itemid_t itemid = stack.getItemId(); + if (itemid == cache.stack.getItemId()) { + return; + } + if (itemid) { + tooltip = util::pascal_case( + langs::get(util::str2wstr_utf8(item.caption)) + ); + } else { + tooltip.clear(); + } +} + +void SlotView::drawItemIcon( + Batch2D& batch, + const ItemStack& stack, + const ItemDef& item, + const Assets& assets, + const glm::vec4& tint, + const glm::vec2& pos +) { + const int SLOT_SIZE = InventoryView::SLOT_SIZE; + const auto& previews = assets.require("block-previews"); + batch.setColor(glm::vec4(1.0f)); + switch (item.iconType) { + case ItemIconType::NONE: + break; + case ItemIconType::BLOCK: { + const Block& block = content->blocks.require(item.icon); + batch.texture(previews.getTexture()); + + UVRegion region = previews.get(block.name); + batch.rect( + pos.x, pos.y, SLOT_SIZE, SLOT_SIZE, + 0, 0, 0, region, false, true, tint + ); + break; + } + case ItemIconType::SPRITE: { + auto textureRegion = + util::get_texture_region(assets, item.icon, "blocks:notfound"); + + batch.texture(textureRegion.texture); + batch.rect( + pos.x, pos.y, SLOT_SIZE, SLOT_SIZE, + 0, 0, 0, textureRegion.region, false, true, tint + ); + break; + } + } +} + void SlotView::draw(const DrawContext& pctx, const Assets& assets) { if (bound == nullptr) { return; } - itemid_t itemid = bound->getItemId(); - if (itemid != prevItem) { - if (itemid) { - auto& def = content->getIndices()->items.require(itemid); - tooltip = util::pascal_case( - langs::get(util::str2wstr_utf8(def.caption)) - ); - } else { - tooltip.clear(); - } - } - prevItem = itemid; - - const int slotSize = InventoryView::SLOT_SIZE; - + const auto& indices = *content->getIndices(); const ItemStack& stack = *bound; + const ItemDef& item = indices.items.require(stack.getItemId()); + + if (cache.stack.getCount() != stack.getCount()) { + cache.countStr = std::to_wstring(stack.getCount()); + } + refreshTooltip(stack, item); + cache.stack.set(ItemStack(stack.getItemId(), stack.getCount())); + glm::vec4 tint(1, 1, 1, isEnabled() ? 1 : 0.5f); glm::vec2 pos = calcPos(); glm::vec4 color = getColor(); @@ -144,67 +190,63 @@ void SlotView::draw(const DrawContext& pctx, const Assets& assets) { color = glm::vec4(1, 1, 1, 0.2f); } - auto batch = pctx.getBatch2D(); - batch->setColor(color); + auto& batch = *pctx.getBatch2D(); + if (color.a > 0.0) { - batch->texture(nullptr); + batch.setColor(color); + batch.texture(nullptr); + + const int size = InventoryView::SLOT_SIZE; if (highlighted) { - batch->rect(pos.x-4, pos.y-4, slotSize+8, slotSize+8); + batch.rect(pos.x - 4, pos.y - 4, size + 8, size + 8); } else { - batch->rect(pos.x, pos.y, slotSize, slotSize); + batch.rect(pos.x, pos.y, size, size); } } - - batch->setColor(glm::vec4(1.0f)); - auto previews = assets.get("block-previews"); - auto indices = content->getIndices(); - - auto& item = indices->items.require(stack.getItemId()); - switch (item.iconType) { - case ItemIconType::NONE: - break; - case ItemIconType::BLOCK: { - const Block& cblock = content->blocks.require(item.icon); - batch->texture(previews->getTexture()); - - UVRegion region = previews->get(cblock.name); - batch->rect( - pos.x, pos.y, slotSize, slotSize, - 0, 0, 0, region, false, true, tint); - break; - } - case ItemIconType::SPRITE: { - auto textureRegion = - util::get_texture_region(assets, item.icon, "blocks:notfound"); - - batch->texture(textureRegion.texture); - batch->rect( - pos.x, pos.y, slotSize, slotSize, - 0, 0, 0, textureRegion.region, false, true, tint); - break; - } - } + drawItemIcon(batch, stack, item, assets, tint, pos); if (stack.getCount() > 1 || stack.getFields() != nullptr) { - auto font = assets.get("normal"); - - if (stack.getCount() > 1) { - std::wstring text = std::to_wstring(stack.getCount()); + const auto& font = assets.require("normal"); + drawItemInfo(batch, stack, item, font, pos); + } +} - int x = pos.x+slotSize-text.length()*8; - int y = pos.y+slotSize-16; +void SlotView::drawItemInfo( + Batch2D& batch, + const ItemStack& stack, + const ItemDef& item, + const Font& font, + const glm::vec2& pos +) { + const int SLOT_SIZE = InventoryView::SLOT_SIZE; + if (stack.getCount() > 1) { + const auto& countStr = cache.countStr; + int x = pos.x + SLOT_SIZE - countStr.length() * 8; + int y = pos.y + SLOT_SIZE - 16; - batch->setColor({0, 0, 0, 1.0f}); - font->draw(*batch, text, x+1, y+1, nullptr, 0); - batch->setColor(glm::vec4(1.0f)); - font->draw(*batch, text, x, y, nullptr, 0); + batch.setColor({0, 0, 0, 1.0f}); + font.draw(batch, countStr, x + 1, y + 1, nullptr, 0); + batch.resetColor(); + font.draw(batch, countStr, x, y, nullptr, 0); + } + if (auto ptr = stack.getField("uses")) { + if (!ptr->isInteger()) { + return; } - if (stack.getFields() != nullptr) { - batch->setColor({0, 0, 0, 1.0f}); - font->draw(*batch, L"#", pos.x+1, pos.y+1, nullptr, 0); - batch->setColor(glm::vec4(1.0f)); - font->draw(*batch, L"#", pos.x, pos.y, nullptr, 0); + { + std::wstring text = std::to_wstring(ptr->asInteger()); + batch.setColor({0, 0, 0, 1.0f}); + font.draw(batch, text, pos.x - 2, pos.y - 2, nullptr, 0); + batch.resetColor(); + font.draw(batch, text, pos.x - 3, pos.y - 3, nullptr, 0); + } + { + std::wstring text = std::to_wstring(item.uses); + batch.setColor({0, 0, 0, 1.0f}); + font.draw(batch, text, pos.x - 2, pos.y - 2 + 12, nullptr, 0); + batch.resetColor(); + font.draw(batch, text, pos.x - 3, pos.y - 3 + 12, nullptr, 0); } } } diff --git a/src/graphics/ui/elements/InventoryView.hpp b/src/graphics/ui/elements/InventoryView.hpp index f98bb20c..c43d48fe 100644 --- a/src/graphics/ui/elements/InventoryView.hpp +++ b/src/graphics/ui/elements/InventoryView.hpp @@ -4,15 +4,18 @@ #include "Container.hpp" #include "typedefs.hpp" #include "constants.hpp" +#include "items/ItemStack.hpp" #include #include #include +class Font; class Assets; +class ItemDef; +class Batch2D; class DrawContext; class Content; -class ItemStack; class ContentIndices; class LevelFrontend; class Inventory; @@ -49,6 +52,11 @@ namespace gui { }; class SlotView : public gui::UINode { + struct { + ItemStack stack {}; + std::wstring countStr; + } cache; + const Content* content = nullptr; SlotLayout layout; bool highlighted = false; @@ -56,11 +64,27 @@ namespace gui { int64_t inventoryid = 0; ItemStack* bound = nullptr; - std::wstring tooltip; - itemid_t prevItem = 0; - void performLeftClick(ItemStack& stack, ItemStack& grabbed); void performRightClick(ItemStack& stack, ItemStack& grabbed); + + void drawItemIcon( + Batch2D& batch, + const ItemStack& stack, + const ItemDef& item, + const Assets& assets, + const glm::vec4& tint, + const glm::vec2& pos + ); + + void drawItemInfo( + Batch2D& batch, + const ItemStack& stack, + const ItemDef& item, + const Font& font, + const glm::vec2& pos + ); + + void refreshTooltip(const ItemStack& stack, const ItemDef& item); public: SlotView(SlotLayout layout); diff --git a/src/items/ItemDef.hpp b/src/items/ItemDef.hpp index f6d61208..620a8d4d 100644 --- a/src/items/ItemDef.hpp +++ b/src/items/ItemDef.hpp @@ -28,10 +28,18 @@ struct ItemDef { dv::value properties = nullptr; + /// @brief Item max stack size itemcount_t stackSize = 64; + + /// @brief Item is generated for other content unit (like block) bool generated = false; + + /// @brief Item light emission [r, g, b] where r,g,b in range [0..15] uint8_t emission[4] {0, 0, 0, 0}; + /// @brief Default item uses count + int16_t uses = 100; + ItemIconType iconType = ItemIconType::SPRITE; std::string icon = "blocks:notfound";