Inventory (WIP part I)
This commit is contained in:
parent
fe5cab0db0
commit
5142f3b4e7
@ -1,146 +1,334 @@
|
|||||||
#include "InventoryView.h"
|
#include "InventoryView.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "BlocksPreview.h"
|
#include "BlocksPreview.h"
|
||||||
#include "LevelFrontend.h"
|
#include "LevelFrontend.h"
|
||||||
#include "../window/Events.h"
|
#include "../window/Events.h"
|
||||||
|
#include "../window/input.h"
|
||||||
#include "../assets/Assets.h"
|
#include "../assets/Assets.h"
|
||||||
#include "../graphics/Atlas.h"
|
#include "../graphics/Atlas.h"
|
||||||
#include "../graphics/Shader.h"
|
#include "../graphics/Shader.h"
|
||||||
#include "../graphics/Batch2D.h"
|
#include "../graphics/Batch2D.h"
|
||||||
#include "../graphics/GfxContext.h"
|
#include "../graphics/GfxContext.h"
|
||||||
|
#include "../graphics/Font.h"
|
||||||
#include "../content/Content.h"
|
#include "../content/Content.h"
|
||||||
#include "../items/ItemDef.h"
|
#include "../items/ItemDef.h"
|
||||||
|
#include "../items/Inventory.h"
|
||||||
#include "../maths/voxmaths.h"
|
#include "../maths/voxmaths.h"
|
||||||
#include "../objects/Player.h"
|
#include "../objects/Player.h"
|
||||||
#include "../voxels/Block.h"
|
#include "../voxels/Block.h"
|
||||||
|
#include "../frontend/gui/controls.h"
|
||||||
|
#include "../util/stringutil.h"
|
||||||
|
|
||||||
|
InventoryLayout::InventoryLayout(glm::vec2 size) : size(size) {}
|
||||||
|
|
||||||
|
void InventoryLayout::add(SlotLayout slot) {
|
||||||
|
slots.push_back(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InventoryLayout::setSize(glm::vec2 size) {
|
||||||
|
this->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InventoryLayout::setOrigin(glm::vec2 origin) {
|
||||||
|
this->origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 InventoryLayout::getSize() const {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 InventoryLayout::getOrigin() const {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SlotLayout>& InventoryLayout::getSlots() {
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotLayout::SlotLayout(
|
||||||
|
glm::vec2 position,
|
||||||
|
bool background,
|
||||||
|
bool itemSource,
|
||||||
|
itemsharefunc shareFunc,
|
||||||
|
slotcallback rightClick
|
||||||
|
)
|
||||||
|
: position(position),
|
||||||
|
background(background),
|
||||||
|
itemSource(itemSource),
|
||||||
|
shareFunc(shareFunc),
|
||||||
|
rightClick(rightClick) {}
|
||||||
|
|
||||||
|
InventoryPanel::InventoryPanel(
|
||||||
|
glm::vec2 position,
|
||||||
|
glm::vec2 size,
|
||||||
|
glm::vec4 color)
|
||||||
|
: position(position), size(size), color(color) {}
|
||||||
|
|
||||||
|
InventoryBuilder::InventoryBuilder()
|
||||||
|
: layout(std::make_unique<InventoryLayout>(glm::vec2()))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void InventoryBuilder::addGrid(
|
||||||
|
int cols, int rows,
|
||||||
|
glm::vec2 coord,
|
||||||
|
int padding,
|
||||||
|
SlotLayout slotLayout)
|
||||||
|
{
|
||||||
|
const int slotSize = InventoryView::SLOT_SIZE;
|
||||||
|
const int interval = InventoryView::SLOT_INTERVAL;
|
||||||
|
|
||||||
|
uint width = cols * (slotSize + interval) - interval + padding*2;
|
||||||
|
uint height = rows * (slotSize + interval) - interval + padding*2;
|
||||||
|
|
||||||
|
auto lsize = layout->getSize();
|
||||||
|
if (coord.x + width > lsize.x) {
|
||||||
|
lsize.x = coord.x + width;
|
||||||
|
}
|
||||||
|
if (coord.y + height > lsize.y) {
|
||||||
|
lsize.y = coord.y + height;
|
||||||
|
}
|
||||||
|
layout->setSize(lsize);
|
||||||
|
|
||||||
|
for (int row = 0; row < rows; row++) {
|
||||||
|
for (int col = 0; col < cols; col++) {
|
||||||
|
glm::vec2 position (
|
||||||
|
col * (slotSize + interval) + padding,
|
||||||
|
row * (slotSize + interval) + padding
|
||||||
|
);
|
||||||
|
auto builtSlot = slotLayout;
|
||||||
|
builtSlot.position = position;
|
||||||
|
layout->add(builtSlot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<InventoryLayout> InventoryBuilder::build() {
|
||||||
|
return std::unique_ptr<InventoryLayout>(layout.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotView::SlotView(
|
||||||
|
ItemStack& stack,
|
||||||
|
LevelFrontend* frontend,
|
||||||
|
InventoryInteraction* interaction,
|
||||||
|
const Content* content,
|
||||||
|
SlotLayout layout)
|
||||||
|
: UINode(glm::vec2(), glm::vec2(InventoryView::SLOT_SIZE)),
|
||||||
|
frontend(frontend),
|
||||||
|
interaction(interaction),
|
||||||
|
content(content),
|
||||||
|
stack(stack),
|
||||||
|
layout(layout) {
|
||||||
|
color(glm::vec4(0, 0, 0, 0.2f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// performance disaster
|
||||||
|
void SlotView::draw(Batch2D* batch, Assets* assets) {
|
||||||
|
glm::vec2 coord = calcCoord();
|
||||||
|
|
||||||
|
int slotSize = InventoryView::SLOT_SIZE;
|
||||||
|
|
||||||
|
glm::vec4 tint(1.0f);
|
||||||
|
glm::vec4 color = color_;
|
||||||
|
if (hover_ || highlighted) {
|
||||||
|
tint *= 1.333f;
|
||||||
|
color = glm::vec4(1, 1, 1, 0.2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
batch->color = color;
|
||||||
|
if (color.a > 0.0) {
|
||||||
|
batch->texture(nullptr);
|
||||||
|
if (highlighted) {
|
||||||
|
batch->rect(coord.x-4, coord.y-4, slotSize+8, slotSize+8);
|
||||||
|
} else {
|
||||||
|
batch->rect(coord.x, coord.y, slotSize, slotSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
batch->color = glm::vec4(1.0f);
|
||||||
|
|
||||||
|
Shader* uiShader = assets->getShader("ui");
|
||||||
|
Viewport viewport(Window::width, Window::height);
|
||||||
|
GfxContext ctx(nullptr, viewport, batch);
|
||||||
|
|
||||||
|
auto preview = frontend->getBlocksPreview();
|
||||||
|
auto indices = content->getIndices();
|
||||||
|
|
||||||
|
ItemDef* item = indices->getItemDef(stack.getItemId());
|
||||||
|
switch (item->iconType) {
|
||||||
|
case item_icon_type::none:
|
||||||
|
break;
|
||||||
|
case item_icon_type::block:
|
||||||
|
batch->render();
|
||||||
|
{
|
||||||
|
GfxContext subctx = ctx.sub();
|
||||||
|
subctx.depthTest(true);
|
||||||
|
subctx.cullFace(true);
|
||||||
|
|
||||||
|
Block* cblock = content->requireBlock(item->icon);
|
||||||
|
preview->begin(&subctx.getViewport());
|
||||||
|
preview->draw(cblock, coord.x, coord.y, slotSize, tint);
|
||||||
|
}
|
||||||
|
uiShader->use();
|
||||||
|
batch->begin();
|
||||||
|
break;
|
||||||
|
case item_icon_type::sprite: {
|
||||||
|
size_t index = item->icon.find(':');
|
||||||
|
std::string name = item->icon.substr(index+1);
|
||||||
|
UVRegion region(0.0f, 0.0, 1.0f, 1.0f);
|
||||||
|
if (index == std::string::npos) {
|
||||||
|
batch->texture(assets->getTexture(name));
|
||||||
|
} else {
|
||||||
|
std::string atlasname = item->icon.substr(0, index);
|
||||||
|
Atlas* atlas = assets->getAtlas(atlasname);
|
||||||
|
if (atlas && atlas->has(name)) {
|
||||||
|
region = atlas->get(name);
|
||||||
|
batch->texture(atlas->getTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
batch->rect(
|
||||||
|
coord.x, coord.y, slotSize, slotSize,
|
||||||
|
0, 0, 0, region, false, true, tint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack.getCount() > 1) {
|
||||||
|
auto font = assets->getFont("normal");
|
||||||
|
std::wstring text = std::to_wstring(stack.getCount());
|
||||||
|
|
||||||
|
int x = coord.x+slotSize-text.length()*8;
|
||||||
|
int y = coord.y+slotSize-16;
|
||||||
|
|
||||||
|
batch->color = glm::vec4(0, 0, 0, 1.0f);
|
||||||
|
font->draw(batch, text, x+1, y+1);
|
||||||
|
batch->color = glm::vec4(1.0f);
|
||||||
|
font->draw(batch, text, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlotView::setHighlighted(bool flag) {
|
||||||
|
highlighted = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SlotView::isHighlighted() const {
|
||||||
|
return highlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlotView::clicked(gui::GUI* gui, int button) {
|
||||||
|
ItemStack& grabbed = interaction->getGrabbedItem();
|
||||||
|
if (button == mousecode::BUTTON_1) {
|
||||||
|
if (Events::pressed(keycode::LEFT_SHIFT)) {
|
||||||
|
if (layout.shareFunc) {
|
||||||
|
layout.shareFunc(stack);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!layout.itemSource && stack.accepts(grabbed)) {
|
||||||
|
stack.move(grabbed, content->getIndices());
|
||||||
|
} else {
|
||||||
|
if (layout.itemSource) {
|
||||||
|
if (grabbed.isEmpty()) {
|
||||||
|
grabbed.set(stack);
|
||||||
|
} else {
|
||||||
|
grabbed.clear();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::swap(grabbed, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (button == mousecode::BUTTON_2) {
|
||||||
|
if (layout.rightClick) {
|
||||||
|
layout.rightClick(stack, grabbed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (layout.itemSource)
|
||||||
|
return;
|
||||||
|
if (grabbed.isEmpty()) {
|
||||||
|
if (!stack.isEmpty()) {
|
||||||
|
grabbed.set(stack);
|
||||||
|
int halfremain = stack.getCount() / 2;
|
||||||
|
grabbed.setCount(stack.getCount() - halfremain);
|
||||||
|
stack.setCount(halfremain);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
stack.set(grabbed);
|
||||||
|
stack.setCount(1);
|
||||||
|
} else {
|
||||||
|
stack.setCount(stack.getCount()+1);
|
||||||
|
}
|
||||||
|
grabbed.setCount(grabbed.getCount()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InventoryView::InventoryView(
|
InventoryView::InventoryView(
|
||||||
int columns,
|
|
||||||
const Content* content,
|
const Content* content,
|
||||||
LevelFrontend* frontend,
|
LevelFrontend* frontend,
|
||||||
std::vector<itemid_t> items)
|
InventoryInteraction* interaction,
|
||||||
: content(content),
|
std::shared_ptr<Inventory> inventory,
|
||||||
|
std::unique_ptr<InventoryLayout> layout)
|
||||||
|
: Container(glm::vec2(), glm::vec2()),
|
||||||
|
content(content),
|
||||||
indices(content->getIndices()),
|
indices(content->getIndices()),
|
||||||
items(items),
|
inventory(inventory),
|
||||||
|
layout(std::move(layout)),
|
||||||
frontend(frontend),
|
frontend(frontend),
|
||||||
columns(columns) {
|
interaction(interaction) {
|
||||||
|
size(this->layout->getSize());
|
||||||
|
color(glm::vec4(0, 0, 0, 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryView::~InventoryView() {
|
InventoryView::~InventoryView() {}
|
||||||
}
|
|
||||||
|
|
||||||
void InventoryView::setPosition(int x, int y) {
|
void InventoryView::build() {
|
||||||
position.x = x;
|
int index = 0;
|
||||||
position.y = y;
|
for (auto& slot : layout->getSlots()) {
|
||||||
}
|
ItemStack& item = inventory->getSlot(index);
|
||||||
|
|
||||||
int InventoryView::getWidth() const {
|
auto view = std::make_shared<SlotView>(
|
||||||
return columns * iconSize + (columns-1) * interval + padding.x * 2;
|
item, frontend, interaction, content, slot
|
||||||
}
|
);
|
||||||
|
if (!slot.background) {
|
||||||
int InventoryView::getHeight() const {
|
view->color(glm::vec4());
|
||||||
uint inv_rows = ceildiv(items.size(), columns);
|
}
|
||||||
return inv_rows * iconSize + (inv_rows-1) * interval + padding.y * 2;
|
slots.push_back(view.get());
|
||||||
}
|
add(view, slot.position);
|
||||||
|
index++;
|
||||||
void InventoryView::setSlotConsumer(slotconsumer consumer) {
|
|
||||||
this->consumer = consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InventoryView::setItems(std::vector<itemid_t> items) {
|
|
||||||
this->items = items;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InventoryView::actAndDraw(const GfxContext* ctx) {
|
|
||||||
Assets* assets = frontend->getAssets();
|
|
||||||
Shader* uiShader = assets->getShader("ui");
|
|
||||||
|
|
||||||
auto viewport = ctx->getViewport();
|
|
||||||
uint inv_w = getWidth();
|
|
||||||
uint inv_h = getHeight();
|
|
||||||
int xs = position.x + padding.x;
|
|
||||||
int ys = position.y + padding.y;
|
|
||||||
|
|
||||||
glm::vec4 tint (1.0f);
|
|
||||||
int mx = Events::cursor.x;
|
|
||||||
int my = Events::cursor.y;
|
|
||||||
|
|
||||||
// background
|
|
||||||
auto batch = ctx->getBatch2D();
|
|
||||||
batch->texture(nullptr);
|
|
||||||
batch->color = glm::vec4(0.0f, 0.0f, 0.0f, 0.5f);
|
|
||||||
batch->rect(position.x, position.y, inv_w, inv_h);
|
|
||||||
batch->render();
|
|
||||||
|
|
||||||
// blocks & items
|
|
||||||
if (Events::scroll) {
|
|
||||||
scroll -= Events::scroll * (iconSize+interval);
|
|
||||||
}
|
}
|
||||||
scroll = std::min(scroll, int(inv_h-viewport.getHeight()));
|
}
|
||||||
scroll = std::max(scroll, 0);
|
|
||||||
|
void InventoryView::setSelected(int index) {
|
||||||
auto blocksPreview = frontend->getBlocksPreview();
|
for (int i = 0; i < int(slots.size()); i++) {
|
||||||
// todo: optimize
|
auto slot = slots[i];
|
||||||
{
|
slot->setHighlighted(i == index);
|
||||||
Window::clearDepth();
|
}
|
||||||
GfxContext subctx = ctx->sub();
|
}
|
||||||
subctx.depthTest(true);
|
|
||||||
subctx.cullFace(true);
|
void InventoryView::setCoord(glm::vec2 coord) {
|
||||||
uint index = 0;
|
Container::setCoord(coord - layout->getOrigin());
|
||||||
for (uint i = 0; i < items.size(); i++) {
|
}
|
||||||
ItemDef* item = indices->getItemDef(items[i]);
|
|
||||||
int x = xs + (iconSize+interval) * (index % columns);
|
void InventoryView::setInventory(std::shared_ptr<Inventory> inventory) {
|
||||||
int y = ys + (iconSize+interval) * (index / columns) - scroll;
|
this->inventory = inventory;
|
||||||
if (y < -int(iconSize+interval) || y >= int(viewport.getHeight())) {
|
}
|
||||||
index++;
|
|
||||||
continue;
|
InventoryLayout* InventoryView::getLayout() const {
|
||||||
}
|
return layout.get();
|
||||||
if (mx > x && mx < x + (int)iconSize && my > y && my < y + (int)iconSize) {
|
}
|
||||||
tint.r *= 1.2f;
|
|
||||||
tint.g *= 1.2f;
|
// performance disaster x2
|
||||||
tint.b *= 1.2f;
|
void InventoryView::draw(Batch2D* batch, Assets* assets) {
|
||||||
if (Events::jclicked(mousecode::BUTTON_1)) {
|
Container::draw(batch, assets);
|
||||||
if (consumer) {
|
Window::clearDepth();
|
||||||
consumer(items[i]);
|
}
|
||||||
}
|
|
||||||
}
|
void InventoryView::drawBackground(Batch2D* batch, Assets* assets) {
|
||||||
} else {
|
glm::vec2 coord = calcCoord();
|
||||||
tint = glm::vec4(1.0f);
|
batch->texture(nullptr);
|
||||||
}
|
batch->color = color_;
|
||||||
switch (item->iconType) {
|
batch->rect(coord.x-1, coord.y-1, size_.x+2, size_.y+2);
|
||||||
case item_icon_type::none:
|
|
||||||
break;
|
|
||||||
case item_icon_type::block: {
|
|
||||||
Block* cblock = content->requireBlock(item->icon);
|
|
||||||
blocksPreview->begin(&ctx->getViewport());
|
|
||||||
blocksPreview->draw(cblock, x, y, iconSize, tint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case item_icon_type::sprite: {
|
|
||||||
batch->begin();
|
|
||||||
uiShader->use();
|
|
||||||
size_t index = item->icon.find(':');
|
|
||||||
std::string name = item->icon.substr(index+1);
|
|
||||||
UVRegion region(0.0f, 0.0, 1.0f, 1.0f);
|
|
||||||
if (index == std::string::npos) {
|
|
||||||
batch->texture(assets->getTexture(name));
|
|
||||||
} else {
|
|
||||||
std::string atlasname = item->icon.substr(0, index);
|
|
||||||
Atlas* atlas = assets->getAtlas(atlasname);
|
|
||||||
if (atlas && atlas->has(name)) {
|
|
||||||
region = atlas->get(name);
|
|
||||||
batch->texture(atlas->getTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
batch->rect(x, y, 48, 48, 0, 0, 0, region, false, true, glm::vec4(1.0f));
|
|
||||||
batch->render();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uiShader->use();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,46 +5,150 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "../frontend/gui/UINode.h"
|
||||||
|
#include "../frontend/gui/panels.h"
|
||||||
|
#include "../frontend/gui/controls.h"
|
||||||
|
#include "../items/ItemStack.h"
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
|
|
||||||
|
class Batch2D;
|
||||||
class Assets;
|
class Assets;
|
||||||
class GfxContext;
|
class GfxContext;
|
||||||
class Content;
|
class Content;
|
||||||
class ContentIndices;
|
class ContentIndices;
|
||||||
class LevelFrontend;
|
class LevelFrontend;
|
||||||
|
class Inventory;
|
||||||
|
|
||||||
typedef std::function<void(itemid_t)> slotconsumer;
|
typedef std::function<void(ItemStack&)> itemsharefunc;
|
||||||
|
typedef std::function<void(ItemStack&, ItemStack&)> slotcallback;
|
||||||
|
|
||||||
class InventoryView {
|
class InventoryInteraction;
|
||||||
|
|
||||||
|
struct SlotLayout {
|
||||||
|
glm::vec2 position;
|
||||||
|
bool background;
|
||||||
|
bool itemSource;
|
||||||
|
itemsharefunc shareFunc;
|
||||||
|
slotcallback rightClick;
|
||||||
|
|
||||||
|
SlotLayout(glm::vec2 position,
|
||||||
|
bool background,
|
||||||
|
bool itemSource,
|
||||||
|
itemsharefunc shareFunc,
|
||||||
|
slotcallback rightClick);
|
||||||
|
};
|
||||||
|
|
||||||
|
// temporary unused
|
||||||
|
struct InventoryPanel {
|
||||||
|
glm::vec2 position;
|
||||||
|
glm::vec2 size;
|
||||||
|
glm::vec4 color;
|
||||||
|
|
||||||
|
InventoryPanel(glm::vec2 position,
|
||||||
|
glm::vec2 size,
|
||||||
|
glm::vec4 color);
|
||||||
|
};
|
||||||
|
|
||||||
|
class InventoryLayout {
|
||||||
|
glm::vec2 size;
|
||||||
|
glm::vec2 origin;
|
||||||
|
std::vector<SlotLayout> slots;
|
||||||
|
public:
|
||||||
|
InventoryLayout(glm::vec2 size);
|
||||||
|
|
||||||
|
void add(SlotLayout slot);
|
||||||
|
void setSize(glm::vec2 size);
|
||||||
|
void setOrigin(glm::vec2 origin);
|
||||||
|
|
||||||
|
glm::vec2 getSize() const;
|
||||||
|
glm::vec2 getOrigin() const;
|
||||||
|
|
||||||
|
std::vector<SlotLayout>& getSlots();
|
||||||
|
};
|
||||||
|
|
||||||
|
class InventoryBuilder {
|
||||||
|
std::unique_ptr<InventoryLayout> layout;
|
||||||
|
public:
|
||||||
|
InventoryBuilder();
|
||||||
|
|
||||||
|
void addGrid(
|
||||||
|
int cols, int rows,
|
||||||
|
glm::vec2 coord,
|
||||||
|
int padding,
|
||||||
|
SlotLayout slotLayout);
|
||||||
|
std::unique_ptr<InventoryLayout> build();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SlotView : public gui::UINode {
|
||||||
|
LevelFrontend* frontend;
|
||||||
|
InventoryInteraction* interaction;
|
||||||
|
const Content* const content;
|
||||||
|
ItemStack& stack;
|
||||||
|
bool highlighted = false;
|
||||||
|
|
||||||
|
SlotLayout layout;
|
||||||
|
public:
|
||||||
|
SlotView(ItemStack& stack,
|
||||||
|
LevelFrontend* frontend,
|
||||||
|
InventoryInteraction* interaction,
|
||||||
|
const Content* content,
|
||||||
|
SlotLayout layout);
|
||||||
|
|
||||||
|
virtual void draw(Batch2D* batch, Assets* assets) override;
|
||||||
|
|
||||||
|
void setHighlighted(bool flag);
|
||||||
|
bool isHighlighted() const;
|
||||||
|
|
||||||
|
virtual void clicked(gui::GUI*, int) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class InventoryView : public gui::Container {
|
||||||
const Content* content;
|
const Content* content;
|
||||||
const ContentIndices* indices;
|
const ContentIndices* indices;
|
||||||
std::vector<itemid_t> items;
|
|
||||||
slotconsumer consumer = nullptr;
|
std::shared_ptr<Inventory> inventory;
|
||||||
|
std::unique_ptr<InventoryLayout> layout;
|
||||||
LevelFrontend* frontend;
|
LevelFrontend* frontend;
|
||||||
|
InventoryInteraction* interaction;
|
||||||
|
|
||||||
|
std::vector<SlotView*> slots;
|
||||||
|
|
||||||
int scroll = 0;
|
int scroll = 0;
|
||||||
int columns;
|
|
||||||
uint iconSize = 48;
|
|
||||||
uint interval = 4;
|
|
||||||
glm::ivec2 padding {interval, interval};
|
|
||||||
glm::ivec2 position {0, 0};
|
|
||||||
public:
|
public:
|
||||||
InventoryView(
|
InventoryView(
|
||||||
int columns,
|
|
||||||
const Content* content,
|
const Content* content,
|
||||||
LevelFrontend* frontend,
|
LevelFrontend* frontend,
|
||||||
std::vector<itemid_t> items);
|
InventoryInteraction* interaction,
|
||||||
|
std::shared_ptr<Inventory> inventory,
|
||||||
|
std::unique_ptr<InventoryLayout> layout);
|
||||||
|
|
||||||
virtual ~InventoryView();
|
virtual ~InventoryView();
|
||||||
|
|
||||||
virtual void actAndDraw(const GfxContext* ctx);
|
void build();
|
||||||
|
|
||||||
void setItems(std::vector<itemid_t> items);
|
virtual void draw(Batch2D* batch, Assets* assets) override;
|
||||||
|
virtual void drawBackground(Batch2D* batch, Assets* assets) override;
|
||||||
|
|
||||||
void setPosition(int x, int y);
|
void setInventory(std::shared_ptr<Inventory> inventory);
|
||||||
int getWidth() const;
|
|
||||||
int getHeight() const;
|
virtual void setCoord(glm::vec2 coord) override;
|
||||||
void setSlotConsumer(slotconsumer consumer);
|
|
||||||
|
InventoryLayout* getLayout() const;
|
||||||
|
|
||||||
|
void setSelected(int index);
|
||||||
|
|
||||||
|
static const int SLOT_INTERVAL = 4;
|
||||||
|
static const int SLOT_SIZE = 48;
|
||||||
|
};
|
||||||
|
|
||||||
|
class InventoryInteraction {
|
||||||
|
ItemStack grabbedItem;
|
||||||
|
public:
|
||||||
|
InventoryInteraction() = default;
|
||||||
|
|
||||||
|
ItemStack& getGrabbedItem() {
|
||||||
|
return grabbedItem;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FRONTEND_INVENTORY_VIEW_H_
|
#endif // FRONTEND_INVENTORY_VIEW_H_
|
||||||
|
|||||||
@ -28,6 +28,8 @@
|
|||||||
#include "../settings.h"
|
#include "../settings.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
#include "../items/ItemDef.h"
|
#include "../items/ItemDef.h"
|
||||||
|
#include "../items/ItemStack.h"
|
||||||
|
#include "../items/Inventory.h"
|
||||||
#include "LevelFrontend.h"
|
#include "LevelFrontend.h"
|
||||||
#include "graphics/Skybox.h"
|
#include "graphics/Skybox.h"
|
||||||
|
|
||||||
@ -169,8 +171,10 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible
|
|||||||
shader->uniform3f("u_cameraPos", camera->position);
|
shader->uniform3f("u_cameraPos", camera->position);
|
||||||
shader->uniform1i("u_cubemap", 1);
|
shader->uniform1i("u_cubemap", 1);
|
||||||
{
|
{
|
||||||
itemid_t id = level->player->getChosenItem();
|
auto player = level->player;
|
||||||
ItemDef* item = indices->getItemDef(id);
|
auto inventory = player->getInventory();
|
||||||
|
ItemStack& stack = inventory->getSlot(player->getChosenSlot());
|
||||||
|
ItemDef* item = indices->getItemDef(stack.getItemId());
|
||||||
assert(item != nullptr);
|
assert(item != nullptr);
|
||||||
float multiplier = 0.5f;
|
float multiplier = 0.5f;
|
||||||
shader->uniform3f("u_torchlightColor",
|
shader->uniform3f("u_torchlightColor",
|
||||||
|
|||||||
@ -10,8 +10,6 @@ using gui::Align;
|
|||||||
using glm::vec2;
|
using glm::vec2;
|
||||||
using glm::vec4;
|
using glm::vec4;
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
UINode::UINode(vec2 coord, vec2 size) : coord(coord), size_(size) {
|
UINode::UINode(vec2 coord, vec2 size) : coord(coord), size_(size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +83,7 @@ shared_ptr<UINode> UINode::getAt(vec2 pos, shared_ptr<UINode> self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool UINode::isInteractive() const {
|
bool UINode::isInteractive() const {
|
||||||
return interactive;
|
return interactive && visible();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UINode::setInteractive(bool flag) {
|
void UINode::setInteractive(bool flag) {
|
||||||
|
|||||||
@ -44,6 +44,7 @@
|
|||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
#include "../core_defs.h"
|
#include "../core_defs.h"
|
||||||
#include "../items/ItemDef.h"
|
#include "../items/ItemDef.h"
|
||||||
|
#include "../items/Inventory.h"
|
||||||
|
|
||||||
using glm::vec2;
|
using glm::vec2;
|
||||||
using glm::vec3;
|
using glm::vec3;
|
||||||
@ -163,26 +164,142 @@ void HudRenderer::createDebugPanel(Engine* engine) {
|
|||||||
panel->refresh();
|
panel->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<InventoryView> HudRenderer::createContentAccess() {
|
||||||
|
auto level = frontend->getLevel();
|
||||||
|
auto content = level->content;
|
||||||
|
auto indices = content->getIndices();
|
||||||
|
auto player = level->player;
|
||||||
|
auto inventory = player->getInventory();
|
||||||
|
|
||||||
|
int itemsCount = indices->countItemDefs();
|
||||||
|
auto accessInventory = std::make_shared<Inventory>(itemsCount);
|
||||||
|
for (int id = 1; id < itemsCount; id++) {
|
||||||
|
accessInventory->getSlot(id-1).set(ItemStack(id, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
const int slotSize = InventoryView::SLOT_SIZE;
|
||||||
|
const int interval = InventoryView::SLOT_INTERVAL;
|
||||||
|
int padding = 8;
|
||||||
|
|
||||||
|
int columns = 8;
|
||||||
|
int rows = ceildiv(itemsCount-1, columns);
|
||||||
|
uint cawidth = columns * (slotSize + interval) - interval + padding;
|
||||||
|
uint caheight = rows * (slotSize + interval) - interval + padding*2;
|
||||||
|
auto layout = std::make_unique<InventoryLayout>(glm::vec2(cawidth, caheight));
|
||||||
|
for (int i = 0; i < itemsCount-1; i++) {
|
||||||
|
int row = i / columns;
|
||||||
|
int col = i % columns;
|
||||||
|
glm::vec2 position (
|
||||||
|
col * slotSize + (col-1) * interval + padding,
|
||||||
|
row * slotSize + (row-1) * interval + padding
|
||||||
|
);
|
||||||
|
layout->add(SlotLayout(position, false, true,
|
||||||
|
[=](ItemStack& item) {
|
||||||
|
auto copy = ItemStack(item);
|
||||||
|
inventory->move(copy, indices);
|
||||||
|
},
|
||||||
|
[=](ItemStack& item, ItemStack& grabbed) {
|
||||||
|
inventory->getSlot(player->getChosenSlot()).set(item);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
auto contentAccess = std::make_shared<InventoryView>(
|
||||||
|
content,
|
||||||
|
frontend,
|
||||||
|
interaction.get(),
|
||||||
|
accessInventory,
|
||||||
|
std::move(layout)
|
||||||
|
);
|
||||||
|
contentAccess->build();
|
||||||
|
return contentAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<InventoryView> HudRenderer::createHotbar() {
|
||||||
|
auto level = frontend->getLevel();
|
||||||
|
auto player = level->player;
|
||||||
|
auto inventory = player->getInventory();
|
||||||
|
auto content = level->content;
|
||||||
|
|
||||||
|
const int slotSize = InventoryView::SLOT_SIZE;
|
||||||
|
const int interval = InventoryView::SLOT_INTERVAL;
|
||||||
|
|
||||||
|
int padding = 4;
|
||||||
|
uint width = 10 * (slotSize + interval) - interval + padding*2;
|
||||||
|
uint height = slotSize + padding * 2;
|
||||||
|
auto layout = std::make_unique<InventoryLayout>(glm::vec2(width, height));
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
glm::vec2 position (i * (slotSize + interval) + padding, padding);
|
||||||
|
layout->add(SlotLayout(position, false, false, nullptr, nullptr));
|
||||||
|
}
|
||||||
|
layout->setOrigin(glm::vec2(width / 2, 0));
|
||||||
|
auto view = std::make_shared<InventoryView>(
|
||||||
|
content,
|
||||||
|
frontend,
|
||||||
|
interaction.get(),
|
||||||
|
inventory,
|
||||||
|
std::move(layout)
|
||||||
|
);
|
||||||
|
view->build();
|
||||||
|
view->setInteractive(false);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<InventoryView> HudRenderer::createInventory() {
|
||||||
|
auto level = frontend->getLevel();
|
||||||
|
auto player = level->player;
|
||||||
|
auto inventory = player->getInventory();
|
||||||
|
auto content = level->content;
|
||||||
|
|
||||||
|
SlotLayout slotLayout(glm::vec2(), true, false, [=](ItemStack& stack) {
|
||||||
|
stack.clear();
|
||||||
|
}, nullptr);
|
||||||
|
|
||||||
|
int columns = 10;
|
||||||
|
int rows = ceildiv(inventory->size(), columns);
|
||||||
|
int padding = 4;
|
||||||
|
|
||||||
|
InventoryBuilder builder;
|
||||||
|
builder.addGrid(columns, rows, glm::vec2(), padding, slotLayout);
|
||||||
|
auto layout = builder.build();
|
||||||
|
|
||||||
|
auto view = std::make_shared<InventoryView>(
|
||||||
|
content,
|
||||||
|
frontend,
|
||||||
|
interaction.get(),
|
||||||
|
inventory,
|
||||||
|
std::move(layout)
|
||||||
|
);
|
||||||
|
view->build();
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
HudRenderer::HudRenderer(Engine* engine, LevelFrontend* frontend)
|
HudRenderer::HudRenderer(Engine* engine, LevelFrontend* frontend)
|
||||||
: assets(engine->getAssets()),
|
: assets(engine->getAssets()),
|
||||||
gui(engine->getGUI()),
|
gui(engine->getGUI()),
|
||||||
frontend(frontend) {
|
frontend(frontend)
|
||||||
|
{
|
||||||
auto level = frontend->getLevel();
|
|
||||||
auto menu = gui->getMenu();
|
auto menu = gui->getMenu();
|
||||||
auto content = level->content;
|
|
||||||
auto indices = content->getIndices();
|
|
||||||
|
|
||||||
std::vector<itemid_t> items;
|
interaction = std::make_unique<InventoryInteraction>();
|
||||||
for (itemid_t id = 1; id < indices->countItemDefs(); id++) {
|
grabbedItemView = std::make_shared<SlotView>(
|
||||||
items.push_back(id);
|
interaction->getGrabbedItem(),
|
||||||
}
|
frontend,
|
||||||
contentAccess.reset(new InventoryView(8, content, frontend, items));
|
interaction.get(),
|
||||||
contentAccess->setSlotConsumer([=](blockid_t id) {
|
frontend->getLevel()->content,
|
||||||
level->player->setChosenItem(id);
|
SlotLayout(glm::vec2(), false, false, nullptr, nullptr)
|
||||||
});
|
);
|
||||||
|
grabbedItemView->color(glm::vec4());
|
||||||
|
grabbedItemView->setInteractive(false);
|
||||||
|
|
||||||
hotbarView.reset(new InventoryView(1, content, frontend, std::vector<itemid_t> {0}));
|
contentAccess = createContentAccess();
|
||||||
|
contentAccessPanel = std::make_shared<Panel>(
|
||||||
|
contentAccess->size(), vec4(0.0f), 0.0f
|
||||||
|
);
|
||||||
|
contentAccessPanel->color(glm::vec4());
|
||||||
|
contentAccessPanel->add(contentAccess);
|
||||||
|
contentAccessPanel->scrollable(true);
|
||||||
|
|
||||||
|
hotbarView = createHotbar();
|
||||||
|
inventoryView = createInventory();
|
||||||
|
|
||||||
uicamera = new Camera(vec3(), 1);
|
uicamera = new Camera(vec3(), 1);
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
@ -191,10 +308,18 @@ HudRenderer::HudRenderer(Engine* engine, LevelFrontend* frontend)
|
|||||||
createDebugPanel(engine);
|
createDebugPanel(engine);
|
||||||
menu->reset();
|
menu->reset();
|
||||||
|
|
||||||
gui->add(this->debugPanel);
|
gui->add(debugPanel);
|
||||||
|
gui->add(contentAccessPanel);
|
||||||
|
gui->add(hotbarView);
|
||||||
|
gui->add(inventoryView);
|
||||||
|
gui->add(grabbedItemView);
|
||||||
}
|
}
|
||||||
|
|
||||||
HudRenderer::~HudRenderer() {
|
HudRenderer::~HudRenderer() {
|
||||||
|
gui->remove(grabbedItemView);
|
||||||
|
gui->remove(inventoryView);
|
||||||
|
gui->remove(hotbarView);
|
||||||
|
gui->remove(contentAccessPanel);
|
||||||
gui->remove(debugPanel);
|
gui->remove(debugPanel);
|
||||||
delete uicamera;
|
delete uicamera;
|
||||||
}
|
}
|
||||||
@ -206,7 +331,12 @@ void HudRenderer::drawDebug(int fps){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HudRenderer::update(bool visible) {
|
void HudRenderer::update(bool visible) {
|
||||||
|
auto level = frontend->getLevel();
|
||||||
|
auto player = level->player;
|
||||||
auto menu = gui->getMenu();
|
auto menu = gui->getMenu();
|
||||||
|
|
||||||
|
menu->visible(pause);
|
||||||
|
|
||||||
if (!visible && inventoryOpen) {
|
if (!visible && inventoryOpen) {
|
||||||
inventoryOpen = false;
|
inventoryOpen = false;
|
||||||
}
|
}
|
||||||
@ -232,13 +362,35 @@ void HudRenderer::update(bool visible) {
|
|||||||
if ((pause || inventoryOpen) == Events::_cursor_locked) {
|
if ((pause || inventoryOpen) == Events::_cursor_locked) {
|
||||||
Events::toggleCursor();
|
Events::toggleCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec2 invSize = contentAccessPanel->size();
|
||||||
|
inventoryView->visible(inventoryOpen);
|
||||||
|
contentAccessPanel->visible(inventoryOpen);
|
||||||
|
contentAccessPanel->size(glm::vec2(invSize.x, Window::height));
|
||||||
|
|
||||||
|
for (int i = keycode::NUM_1; i <= keycode::NUM_9; i++) {
|
||||||
|
if (Events::jpressed(i)) {
|
||||||
|
player->setChosenSlot(i - keycode::NUM_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Events::jpressed(keycode::NUM_0)) {
|
||||||
|
player->setChosenSlot(9);
|
||||||
|
}
|
||||||
|
if (!inventoryOpen && Events::scroll) {
|
||||||
|
int slot = player->getChosenSlot();
|
||||||
|
slot = (slot + Events::scroll) % 10;
|
||||||
|
if (slot < 0) {
|
||||||
|
slot += 10;
|
||||||
|
}
|
||||||
|
player->setChosenSlot(slot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HudRenderer::drawOverlay(const GfxContext& ctx) {
|
void HudRenderer::drawOverlay(const GfxContext& ctx) {
|
||||||
if (pause) {
|
if (pause) {
|
||||||
Shader* uishader = assets->getShader("ui");
|
Shader* uishader = assets->getShader("ui");
|
||||||
uishader->use();
|
uishader->use();
|
||||||
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
|
uishader->uniformMatrix("u_projview", uicamera->getProjView());
|
||||||
|
|
||||||
const Viewport& viewport = ctx.getViewport();
|
const Viewport& viewport = ctx.getViewport();
|
||||||
const uint width = viewport.getWidth();
|
const uint width = viewport.getWidth();
|
||||||
@ -271,12 +423,11 @@ void HudRenderer::draw(const GfxContext& ctx){
|
|||||||
|
|
||||||
Shader* uishader = assets->getShader("ui");
|
Shader* uishader = assets->getShader("ui");
|
||||||
uishader->use();
|
uishader->use();
|
||||||
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
|
uishader->uniformMatrix("u_projview", uicamera->getProjView());
|
||||||
|
|
||||||
// Draw selected item preview
|
// Draw selected item preview
|
||||||
hotbarView->setPosition(width-60, height-60);
|
hotbarView->setCoord(glm::vec2(width/2, height-65));
|
||||||
hotbarView->setItems({player->getChosenItem()});
|
hotbarView->setSelected(player->getChosenSlot());
|
||||||
hotbarView->actAndDraw(&ctx);
|
|
||||||
|
|
||||||
// Crosshair
|
// Crosshair
|
||||||
batch->begin();
|
batch->begin();
|
||||||
@ -289,10 +440,20 @@ void HudRenderer::draw(const GfxContext& ctx){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inventoryOpen) {
|
if (inventoryOpen) {
|
||||||
// draw content access panel (all available items)
|
auto caLayout = contentAccess->getLayout();
|
||||||
contentAccess->setPosition(viewport.getWidth()-contentAccess->getWidth(), 0);
|
auto invLayout = inventoryView->getLayout();
|
||||||
contentAccess->actAndDraw(&ctx);
|
float caWidth = caLayout->getSize().x;
|
||||||
|
glm::vec2 invSize = invLayout->getSize();
|
||||||
|
|
||||||
|
float width = viewport.getWidth();
|
||||||
|
|
||||||
|
inventoryView->setCoord(glm::vec2(
|
||||||
|
glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x),
|
||||||
|
height/2-invSize.y/2
|
||||||
|
));
|
||||||
|
contentAccessPanel->setCoord(glm::vec2(width-caWidth, 0));
|
||||||
}
|
}
|
||||||
|
grabbedItemView->setCoord(glm::vec2(Events::cursor));
|
||||||
batch->render();
|
batch->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,12 +15,15 @@ class Assets;
|
|||||||
class Player;
|
class Player;
|
||||||
class Level;
|
class Level;
|
||||||
class Engine;
|
class Engine;
|
||||||
|
class SlotView;
|
||||||
class InventoryView;
|
class InventoryView;
|
||||||
class LevelFrontend;
|
class LevelFrontend;
|
||||||
|
class InventoryInteraction;
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
class GUI;
|
class GUI;
|
||||||
class UINode;
|
class UINode;
|
||||||
|
class Panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
class HudRenderer {
|
class HudRenderer {
|
||||||
@ -34,13 +37,21 @@ class HudRenderer {
|
|||||||
bool inventoryOpen = false;
|
bool inventoryOpen = false;
|
||||||
bool pause = false;
|
bool pause = false;
|
||||||
|
|
||||||
std::unique_ptr<InventoryView> contentAccess;
|
std::shared_ptr<gui::Panel> contentAccessPanel;
|
||||||
std::unique_ptr<InventoryView> hotbarView;
|
std::shared_ptr<InventoryView> contentAccess;
|
||||||
|
std::shared_ptr<InventoryView> hotbarView;
|
||||||
|
std::shared_ptr<InventoryView> inventoryView;
|
||||||
std::shared_ptr<gui::UINode> debugPanel;
|
std::shared_ptr<gui::UINode> debugPanel;
|
||||||
|
std::unique_ptr<InventoryInteraction> interaction;
|
||||||
|
std::shared_ptr<SlotView> grabbedItemView;
|
||||||
gui::GUI* gui;
|
gui::GUI* gui;
|
||||||
LevelFrontend* frontend;
|
LevelFrontend* frontend;
|
||||||
|
|
||||||
void createDebugPanel(Engine* engine);
|
void createDebugPanel(Engine* engine);
|
||||||
|
|
||||||
|
std::shared_ptr<InventoryView> createContentAccess();
|
||||||
|
std::shared_ptr<InventoryView> createHotbar();
|
||||||
|
std::shared_ptr<InventoryView> createInventory();
|
||||||
public:
|
public:
|
||||||
HudRenderer(Engine* engine, LevelFrontend* frontend);
|
HudRenderer(Engine* engine, LevelFrontend* frontend);
|
||||||
~HudRenderer();
|
~HudRenderer();
|
||||||
|
|||||||
74
src/items/Inventory.cpp
Normal file
74
src/items/Inventory.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "Inventory.h"
|
||||||
|
|
||||||
|
Inventory::Inventory(size_t size) : slots(size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack& Inventory::getSlot(size_t index) {
|
||||||
|
return slots[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Inventory::findEmptySlot(size_t begin, size_t end) const {
|
||||||
|
end = std::min(slots.size(), end);
|
||||||
|
for (size_t i = begin; i < end; i++) {
|
||||||
|
if (slots[i].isEmpty()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Inventory::findSlotByItem(itemid_t id, size_t begin, size_t end) {
|
||||||
|
end = std::min(slots.size(), end);
|
||||||
|
for (size_t i = begin; i < end; i++) {
|
||||||
|
if (slots[i].getItemId() == id) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inventory::move(
|
||||||
|
ItemStack& item,
|
||||||
|
const ContentIndices* indices,
|
||||||
|
size_t begin,
|
||||||
|
size_t end)
|
||||||
|
{
|
||||||
|
end = std::min(slots.size(), end);
|
||||||
|
for (size_t i = begin; i < end && !item.isEmpty(); i++) {
|
||||||
|
ItemStack& slot = slots[i];
|
||||||
|
if (slot.accepts(item)) {
|
||||||
|
slot.move(item, indices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inventory::read(const dynamic::Map* src) {
|
||||||
|
auto slotsarr = src->list("slots");
|
||||||
|
size_t slotscount = std::min(slotsarr->size(), slots.size());
|
||||||
|
for (size_t i = 0; i < slotscount; i++) {
|
||||||
|
auto item = slotsarr->map(i);
|
||||||
|
itemid_t id = item->getInt("id", ITEM_EMPTY);
|
||||||
|
itemcount_t count = item->getInt("count", 0);
|
||||||
|
auto& slot = slots[i];
|
||||||
|
slot.set(ItemStack(id, count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<dynamic::Map> Inventory::write() const {
|
||||||
|
auto map = std::make_unique<dynamic::Map>();
|
||||||
|
auto& slotsarr = map->putList("slots");
|
||||||
|
for (size_t i = 0; i < slots.size(); i++) {
|
||||||
|
auto& item = slots[i];
|
||||||
|
itemid_t id = item.getItemId();
|
||||||
|
itemcount_t count = item.getCount();
|
||||||
|
|
||||||
|
auto& slotmap = slotsarr.putMap();
|
||||||
|
slotmap.put("id", id);
|
||||||
|
if (count) {
|
||||||
|
slotmap.put("count", count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t Inventory::npos = -1;
|
||||||
41
src/items/Inventory.h
Normal file
41
src/items/Inventory.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef ITEMS_INVENTORY_H_
|
||||||
|
#define ITEMS_INVENTORY_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "ItemStack.h"
|
||||||
|
|
||||||
|
#include "../typedefs.h"
|
||||||
|
#include "../data/dynamic.h"
|
||||||
|
|
||||||
|
class ContentIndices;
|
||||||
|
|
||||||
|
class Inventory {
|
||||||
|
std::vector<ItemStack> slots;
|
||||||
|
public:
|
||||||
|
Inventory(size_t size);
|
||||||
|
|
||||||
|
ItemStack& getSlot(size_t index);
|
||||||
|
size_t findEmptySlot(size_t begin=0, size_t end=-1) const;
|
||||||
|
size_t findSlotByItem(itemid_t id, size_t begin=0, size_t end=-1);
|
||||||
|
|
||||||
|
inline size_t size() const {
|
||||||
|
return slots.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void move(
|
||||||
|
ItemStack& item,
|
||||||
|
const ContentIndices* indices,
|
||||||
|
size_t begin=0,
|
||||||
|
size_t end=-1);
|
||||||
|
|
||||||
|
/* deserializing inventory */
|
||||||
|
void read(const dynamic::Map* src);
|
||||||
|
/* serializing inventory */
|
||||||
|
std::unique_ptr<dynamic::Map> write() const;
|
||||||
|
|
||||||
|
static const size_t npos;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ITEMS_INVENTORY_H_
|
||||||
40
src/items/ItemStack.cpp
Normal file
40
src/items/ItemStack.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include "ItemStack.h"
|
||||||
|
|
||||||
|
#include "ItemDef.h"
|
||||||
|
#include "../content/Content.h"
|
||||||
|
|
||||||
|
ItemStack::ItemStack() : item(ITEM_EMPTY), count(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack::ItemStack(itemid_t item, itemcount_t count) : item(item), count(count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemStack::set(const ItemStack& item) {
|
||||||
|
this->item = item.item;
|
||||||
|
this->count = item.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemStack::accepts(const ItemStack& other) const {
|
||||||
|
if (isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return item == other.getItemId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemStack::move(ItemStack& item, const ContentIndices* indices) {
|
||||||
|
auto def = indices->getItemDef(item.getItemId());
|
||||||
|
int count = std::min(item.count, def->stackSize-this->count);
|
||||||
|
if (isEmpty()) {
|
||||||
|
set(ItemStack(item.getItemId(), count));
|
||||||
|
} else {
|
||||||
|
setCount(this->count + count);
|
||||||
|
}
|
||||||
|
item.setCount(item.count-count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemStack::setCount(itemcount_t count) {
|
||||||
|
this->count = count;
|
||||||
|
if (count == 0) {
|
||||||
|
item = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/items/ItemStack.h
Normal file
40
src/items/ItemStack.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef ITEMS_ITEM_STACK_H_
|
||||||
|
#define ITEMS_ITEM_STACK_H_
|
||||||
|
|
||||||
|
#include "../typedefs.h"
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
class ContentIndices;
|
||||||
|
|
||||||
|
class ItemStack {
|
||||||
|
itemid_t item;
|
||||||
|
itemcount_t count;
|
||||||
|
public:
|
||||||
|
ItemStack();
|
||||||
|
|
||||||
|
ItemStack(itemid_t item, itemcount_t count);
|
||||||
|
|
||||||
|
void set(const ItemStack& item);
|
||||||
|
void setCount(itemcount_t count);
|
||||||
|
|
||||||
|
bool accepts(const ItemStack& item) const;
|
||||||
|
void move(ItemStack& item, const ContentIndices* indices);
|
||||||
|
|
||||||
|
inline void clear() {
|
||||||
|
set(ItemStack(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isEmpty() const {
|
||||||
|
return item == ITEM_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline itemid_t getItemId() const {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline itemcount_t getCount() const {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ITEMS_ITEM_STACK_H_
|
||||||
@ -13,6 +13,8 @@
|
|||||||
#include "../window/Events.h"
|
#include "../window/Events.h"
|
||||||
#include "../window/input.h"
|
#include "../window/input.h"
|
||||||
#include "../items/ItemDef.h"
|
#include "../items/ItemDef.h"
|
||||||
|
#include "../items/ItemStack.h"
|
||||||
|
#include "../items/Inventory.h"
|
||||||
#include "scripting/scripting.h"
|
#include "scripting/scripting.h"
|
||||||
#include "BlocksController.h"
|
#include "BlocksController.h"
|
||||||
|
|
||||||
@ -239,7 +241,9 @@ void PlayerController::updateInteraction(){
|
|||||||
int z = iend.z;
|
int z = iend.z;
|
||||||
uint8_t states = 0;
|
uint8_t states = 0;
|
||||||
|
|
||||||
ItemDef* item = indices->getItemDef(player->getChosenItem());
|
auto inventory = player->getInventory();
|
||||||
|
ItemStack& stack = inventory->getSlot(player->getChosenSlot());
|
||||||
|
ItemDef* item = indices->getItemDef(stack.getItemId());
|
||||||
Block* def = indices->getBlockDef(item->rt.placingBlock);
|
Block* def = indices->getBlockDef(item->rt.placingBlock);
|
||||||
if (def && def->rotatable){
|
if (def && def->rotatable){
|
||||||
const std::string& name = def->rotations.name;
|
const std::string& name = def->rotations.name;
|
||||||
@ -311,7 +315,18 @@ void PlayerController::updateInteraction(){
|
|||||||
}
|
}
|
||||||
if (Events::jactive(BIND_PLAYER_PICK)){
|
if (Events::jactive(BIND_PLAYER_PICK)){
|
||||||
Block* block = indices->getBlockDef(chunks->get(x,y,z)->id);
|
Block* block = indices->getBlockDef(chunks->get(x,y,z)->id);
|
||||||
player->setChosenItem(block->rt.pickingItem);
|
itemid_t id = block->rt.pickingItem;
|
||||||
|
auto inventory = player->getInventory();
|
||||||
|
size_t slotid = inventory->findSlotByItem(id);
|
||||||
|
if (slotid == Inventory::npos) {
|
||||||
|
slotid = player->getChosenSlot();
|
||||||
|
} else {
|
||||||
|
player->setChosenSlot(slotid);
|
||||||
|
}
|
||||||
|
ItemStack& stack = inventory->getSlot(slotid);
|
||||||
|
if (stack.getItemId() != id) {
|
||||||
|
stack.set(ItemStack(id, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectedBlockId = -1;
|
selectedBlockId = -1;
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "../world/Level.h"
|
#include "../world/Level.h"
|
||||||
#include "../window/Events.h"
|
#include "../window/Events.h"
|
||||||
#include "../window/Camera.h"
|
#include "../window/Camera.h"
|
||||||
|
#include "../items/Inventory.h"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
@ -18,12 +19,16 @@ const float JUMP_FORCE = 8.0f;
|
|||||||
|
|
||||||
Player::Player(glm::vec3 position, float speed) :
|
Player::Player(glm::vec3 position, float speed) :
|
||||||
speed(speed),
|
speed(speed),
|
||||||
chosenItem(0),
|
chosenSlot(0),
|
||||||
camera(new Camera(position, glm::radians(90.0f))),
|
camera(new Camera(position, glm::radians(90.0f))),
|
||||||
spCamera(new Camera(position, glm::radians(90.0f))),
|
spCamera(new Camera(position, glm::radians(90.0f))),
|
||||||
tpCamera(new Camera(position, glm::radians(90.0f))),
|
tpCamera(new Camera(position, glm::radians(90.0f))),
|
||||||
currentCamera(camera),
|
currentCamera(camera),
|
||||||
hitbox(new Hitbox(position, glm::vec3(0.3f,0.9f,0.3f))) {
|
hitbox(new Hitbox(position, glm::vec3(0.3f,0.9f,0.3f))),
|
||||||
|
inventory(new Inventory(40)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Player::~Player() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::update(
|
void Player::update(
|
||||||
@ -118,14 +123,18 @@ void Player::teleport(glm::vec3 position) {
|
|||||||
hitbox->position = position;
|
hitbox->position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::setChosenItem(itemid_t id) {
|
void Player::setChosenSlot(int index) {
|
||||||
chosenItem = id;
|
chosenSlot = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
itemid_t Player::getChosenItem() const {
|
int Player::getChosenSlot() const {
|
||||||
return chosenItem;
|
return chosenSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Player::getSpeed() const {
|
float Player::getSpeed() const {
|
||||||
return speed;
|
return speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Inventory> Player::getInventory() const {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
class Camera;
|
class Camera;
|
||||||
class Hitbox;
|
class Hitbox;
|
||||||
|
class Inventory;
|
||||||
class PhysicsSolver;
|
class PhysicsSolver;
|
||||||
class Chunks;
|
class Chunks;
|
||||||
class Level;
|
class Level;
|
||||||
@ -30,11 +31,12 @@ struct PlayerInput {
|
|||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
float speed;
|
float speed;
|
||||||
itemid_t chosenItem;
|
int chosenSlot;
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<Camera> camera, spCamera, tpCamera;
|
std::shared_ptr<Camera> camera, spCamera, tpCamera;
|
||||||
std::shared_ptr<Camera> currentCamera;
|
std::shared_ptr<Camera> currentCamera;
|
||||||
std::unique_ptr<Hitbox> hitbox;
|
std::unique_ptr<Hitbox> hitbox;
|
||||||
|
std::shared_ptr<Inventory> inventory;
|
||||||
bool flight = false;
|
bool flight = false;
|
||||||
bool noclip = false;
|
bool noclip = false;
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
@ -43,15 +45,17 @@ public:
|
|||||||
glm::vec2 cam = {};
|
glm::vec2 cam = {};
|
||||||
|
|
||||||
Player(glm::vec3 position, float speed);
|
Player(glm::vec3 position, float speed);
|
||||||
~Player() = default;
|
~Player();
|
||||||
|
|
||||||
void teleport(glm::vec3 position);
|
void teleport(glm::vec3 position);
|
||||||
void update(Level* level, PlayerInput& input, float delta);
|
void update(Level* level, PlayerInput& input, float delta);
|
||||||
|
|
||||||
void setChosenItem(itemid_t id);
|
void setChosenSlot(int index);
|
||||||
|
|
||||||
itemid_t getChosenItem() const;
|
int getChosenSlot() const;
|
||||||
float getSpeed() const;
|
float getSpeed() const;
|
||||||
|
|
||||||
|
std::shared_ptr<Inventory> getInventory() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SRC_OBJECTS_PLAYER_H_ */
|
#endif /* SRC_OBJECTS_PLAYER_H_ */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user